Update help #34

Closed
opened 2026-03-27 22:48:42 +00:00 by maxtkc · 0 comments
Owner

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. Navbar navbar-end div (lines 63–305) is where the ? button goes, alongside existing icon-only ghost buttons (undo/redo, theme toggle).
  • src/modules/modal-utils.tsshowModal() 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 call showModal.
  • src/modules/keyboard-shortcuts.tsshowHelp() (line 290) currently tries to click [data-tab="help"], which doesn't actually work with the radio tab system. ctrl+5 shortcut (line 178) switches to help tab. getShortcutsList() (line 344) returns Array<{ key: string; description: string }> — the source of truth for accurate shortcut display.
  • src/index.tsthis.keyboardShortcuts = new KeyboardShortcuts(this) (line 81). Post-init wiring happens in init(). __APP_VERSION__ is available as a global const (declared line 33).
  • DaisyUI modal scroll pattern: set max-h-[80vh] flex flex-col on modal-box, make the body div flex-1 overflow-y-auto, keep title and action bar outside the scroll region.

Phase 1: Extend modal-utils.ts for dismissable + scrollable modals

The 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.

  • Add dismissable?: boolean to the showModal options interface
  • When dismissable: 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 promise
  • Add a keydown listener on document for Escape when the modal is open; on Escape, close and resolve (same cleanup path as X button). Remove the listener when the modal closes.
  • Change modal-box class to modal-box max-h-[80vh] flex flex-col (always, not just when dismissable — overflow can't hurt non-scrolling modals)
  • Change the body content div from <div class="py-4"> to <div class="flex-1 overflow-y-auto py-4"> so it scrolls independently of the title/actions
  • Add relative to the modal-box so the absolute X button positions correctly

Gotcha: 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 inside showModal that handles both DOM removal and listener cleanup.


Phase 2: Create src/modules/about-modal.ts

A standalone module that assembles the modal HTML and calls showModal. Accepts version: string and shortcuts: Array<{ key: string; description: string }> so it has no dependency on the KeyboardShortcuts class itself.

  • Create src/modules/about-modal.ts exporting function 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 divider or text-sm font-semibold opacity-60 headings between sections):

    About

    edit.gtfs.zone is a browser-based GTFS transit data editor inspired by geojson.io. All data stays in your browser — no server, no account required.

    Version & Source

    • Version: <code class="font-mono">${version}</code>
    • Source code: link to https://git.kcfam.us/gtfs.zone/coloring-book
    • Changelog: link to https://git.kcfam.us/gtfs.zone/coloring-book/raw/branch/main/CHANGELOG.md

    Keyboard Shortcuts

    • Render shortcuts as a <table class="table table-xs w-full"> with columns Key / Action
    • Wrap each key string in <kbd class="kbd kbd-xs"> per token split on +, joined with +

    Resources

    • GTFS Spec Reference: https://gtfs.org/reference/ — "Official file format and field reference"
    • TransitLand Atlas: https://www.transit.land/ — "Real-world GTFS feeds (used by the Load → From TransitLand Atlas feature)"
    • All links open in 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

  • Delete the Help tab radio input (<input ... id="help-tab-radio" ...>) and its associated <div class="tab-content ..."> block (lines 523–779)
  • Add a ? button to navbar-end, after the theme toggle swap label and before the undo/redo group:
    <button id="about-btn" class="btn btn-ghost btn-sm btn-square" title="About / Help (F1)">
      <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
        <path stroke-linecap="round" stroke-linejoin="round" d="M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
      </svg>
    </button>
    

src/modules/keyboard-shortcuts.ts

  • Remove the ctrl+5 shortcut block (lines 178–184) — there is no Help tab to switch to
  • Add setShowHelpHandler(fn: () => void): void method that stores fn in a private field private showHelpHandler?: () => void
  • Update showHelp() to call this.showHelpHandler?.() instead of the broken tab-click code

src/index.ts

  • Import showAboutModal from ./modules/about-modal

  • After this.keyboardShortcuts.initialize(), call:

    const openAbout = () => showAboutModal(__APP_VERSION__, this.keyboardShortcuts.getShortcutsList());
    this.keyboardShortcuts.setShowHelpHandler(openAbout);
    document.getElementById('about-btn')?.addEventListener('click', openAbout);
    
  • Unrelated cleanup: added dismissable: true to 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

Update help It should be accurate

## 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. Navbar `navbar-end` div (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 call `showModal`. - **`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+5` shortcut (line 178) switches to help tab. `getShortcutsList()` (line 344) returns `Array<{ 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 in `init()`. `__APP_VERSION__` is available as a global const (declared line 33). - **DaisyUI modal scroll pattern**: set `max-h-[80vh] flex flex-col` on `modal-box`, make the body div `flex-1 overflow-y-auto`, keep title and action bar outside the scroll region. --- ## Phase 1: Extend `modal-utils.ts` for dismissable + scrollable modals The 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. - [x] Add `dismissable?: boolean` to the `showModal` options interface - [x] When `dismissable: 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 promise - [x] Add a `keydown` listener on `document` for `Escape` when the modal is open; on Escape, close and resolve (same cleanup path as X button). Remove the listener when the modal closes. - [x] Change `modal-box` class to `modal-box max-h-[80vh] flex flex-col` (always, not just when dismissable — overflow can't hurt non-scrolling modals) - [x] Change the body content div from `<div class="py-4">` to `<div class="flex-1 overflow-y-auto py-4">` so it scrolls independently of the title/actions - [x] Add `relative` to the `modal-box` so the absolute X button positions correctly **Gotcha:** 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 inside `showModal` that handles both DOM removal and listener cleanup. --- ## Phase 2: Create `src/modules/about-modal.ts` A standalone module that assembles the modal HTML and calls `showModal`. Accepts `version: string` and `shortcuts: Array<{ key: string; description: string }>` so it has no dependency on the `KeyboardShortcuts` class itself. - [x] Create `src/modules/about-modal.ts` exporting `function showAboutModal(version: string, shortcuts: Array<{ key: string; description: string }>): Promise<void>` - [x] Build the modal body HTML with the following sections (no emojis, no colored alert boxes — use `divider` or `text-sm font-semibold opacity-60` headings between sections): **About** > edit.gtfs.zone is a browser-based GTFS transit data editor inspired by geojson.io. All data stays in your browser — no server, no account required. **Version & Source** - Version: `<code class="font-mono">${version}</code>` - Source code: link to `https://git.kcfam.us/gtfs.zone/coloring-book` - Changelog: link to `https://git.kcfam.us/gtfs.zone/coloring-book/raw/branch/main/CHANGELOG.md` **Keyboard Shortcuts** - Render `shortcuts` as a `<table class="table table-xs w-full">` with columns Key / Action - Wrap each key string in `<kbd class="kbd kbd-xs">` per token split on `+`, joined with `+` **Resources** - GTFS Spec Reference: `https://gtfs.org/reference/` — "Official file format and field reference" - TransitLand Atlas: `https://www.transit.land/` — "Real-world GTFS feeds (used by the Load → From TransitLand Atlas feature)" - All links open in `target="_blank" rel="noopener noreferrer"` - [x] 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`** - [x] Delete the Help tab radio input (`<input ... id="help-tab-radio" ...>`) and its associated `<div class="tab-content ...">` block (lines 523–779) - [x] Add a `?` button to `navbar-end`, after the theme toggle swap label and before the undo/redo group: ```html <button id="about-btn" class="btn btn-ghost btn-sm btn-square" title="About / Help (F1)"> <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"> <path stroke-linecap="round" stroke-linejoin="round" d="M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /> </svg> </button> ``` **`src/modules/keyboard-shortcuts.ts`** - [x] Remove the `ctrl+5` shortcut block (lines 178–184) — there is no Help tab to switch to - [x] Add `setShowHelpHandler(fn: () => void): void` method that stores `fn` in a private field `private showHelpHandler?: () => void` - [x] Update `showHelp()` to call `this.showHelpHandler?.()` instead of the broken tab-click code **`src/index.ts`** - [x] Import `showAboutModal` from `./modules/about-modal` - [x] After `this.keyboardShortcuts.initialize()`, call: ```ts const openAbout = () => showAboutModal(__APP_VERSION__, this.keyboardShortcuts.getShortcutsList()); this.keyboardShortcuts.setShowHelpHandler(openAbout); document.getElementById('about-btn')?.addEventListener('click', openAbout); ``` - [x] Unrelated cleanup: added `dismissable: true` to 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 > **Update help** > It should be accurate
maxtkc self-assigned this 2026-03-27 22:48:42 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
gtfs.zone/coloring-book#34
No description provided.