Mobile follow-up: dock, tab state, crypto.randomUUID fix #74
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#74
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
Three follow-up items from the initial mobile support (#67): (1)
crypto.randomUUIDcrashes on non-HTTPS mobile browsers — needs aMath.random()fallback; (2) the current "peek = tab labels visible" approach should be replaced with DaisyUI's properdockcomponent as a fixed bottom nav, with the bottom sheet sliding above it; (3) switching to the Files or Changes tab should clear the active object selection (pageState → home) on both desktop and mobile, giving a cleaner state model where the active tab and the focused object are always in sync.The dock serves as the primary mobile nav entry point. In the default "closed" state only the dock is visible. Tapping a dock item opens the sheet. Swiping the sheet down dismisses it and clears selection.
Relevant Context
src/modules/tab-lock.ts:8—crypto.randomUUID()crashes on HTTP (non-HTTPS) contexts on mobilesrc/modules/interaction-handler.ts:188— same crashsrc/modules/bottom-sheet.ts—BottomSheetController; currently haspeek/half/full; needsclosedstate replacingpeek, dock integration, dismiss callback;PEEK_PX=56was sized to match tab-label height which the dock now replacessrc/modules/tab-manager.ts—switchToTabdispatcheschangeevent;onTabChangelistens on all radio inputssrc/index.ts:298—setupNavigationTabSwitching()— add tab→state clearing and map-click→sheet-open heresrc/index.html:427–568— DaisyUI radio tabs inside#right-panel; radio inputs haveclass="tab"which renders them as visible labels; these must be hidden on mobile while remaining in DOM (CSS:checkedsibling selectors drive tab content)src/index.html:5— viewport meta lacksviewport-fit=cover(needed for iOS safe area with dock)src/styles/main.css— mobile media query block at bottom; needs dock height var and updated sheet positioning<div class="dock">+<button class="dock-active">+<span class="dock-label">— alreadyposition: fixed; bottom: 0Phase 1: crypto.randomUUID polyfill
Fix crash on non-HTTPS mobile browsers (HTTP dev servers, HTTP deployments).
src/utils/uuid.tswithgenerateId():src/modules/tab-lock.ts:8, replacecrypto.randomUUID()withgenerateId()(import from../utils/uuid)src/modules/interaction-handler.ts:188, replacecrypto.randomUUID()withgenerateId()Phase 2: Tab-aware state clearing (desktop + mobile)
When switching to Files or Changes, clear page state to
home. Switching to Browse does not force any state change — whatever was selected remains. This applies on both desktop and mobile.src/index.ts, insetupNavigationTabSwitching(), add a secondtabManager.onTabChangelistener alongside the existing navigation handler: The sheet stays open — it just now shows Files/Changes content with no selected object.Gotcha:
onTabChangefires for every tab switch including programmatic Browse switches triggered by map clicks. Theifguard excludes'browse'so there is no loop.Phase 3: DaisyUI Dock + BottomSheetController v2
HTML changes (
src/index.html)viewport-fit=coverfor iOS safe area support:<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />#sheet-drag-handlediv from#right-panel(dock area replaces it; a new thin drag strip is added instead)<div id="sheet-top-handle">as first child of#right-panel(replacessheet-drag-handle; same visual pill, samemd:hiddenclass)</body>(DaisyUI dock isposition: fixedso DOM position doesn't matter):input.tabradio element (browse, files, changes), addhidden md:flexso labels are invisible on mobile but remain in DOM for CSS tab-content switchingCSS changes (
src/styles/main.css)@media (max-width: 767px)block:--dock-height: 4rem;to:rootor at top of the block#right-panel:bottom: var(--dock-height)(wasbottom: 0), defaultheight: 0(closed state replaces peek), removeheight: var(--sheet-height, 56px)input.tab { display: none; }and.tabs-bordered { border-bottom: none; }#right-panel.sheet-full .tab-content { overflow-y: auto; }and add same for.sheet-halfRewrite
src/modules/bottom-sheet.tstype Snap = 'closed' | 'half' | 'full'(removepeek, addclosed)PEEK_PX; addCLOSED_PX = 0'closed'private dismissCallbacks: Array<() => void> = []onDismiss(cb: () => void): voidmethodopen(snap: 'half' | 'full' = 'half'): void— callssetSnap(snap, true)close(): void— callssetSnap('closed', true)without firing dismiss callbacks (for programmatic close)resolveSnap: when velocity is strongly negative OR height is belowhalfH / 2, return'closed'and fire dismiss callbacks; otherwise half/full logic unchangedsetSnap('closed'): set height to 0, removesheet-full/sheet-halfclasses, addoverflow: hiddensetupTabExpansion:setupTabExpansion(tabManager)withsetupDock(tabManager):#dock-browse,#dock-files,#dock-changestabManager.switchToTab(tabName),this.open('half'), updatedock-activeclasstabManager.onTabChangeto keepdock-activeclass in sync when tabs switch programmatically#sheet-top-handleidWire in
src/index.tsBottomSheetControllerin a local variableconst bottomSheet = ...bottomSheet.onDismiss(() => void this.pageStateManager.setPageState({ type: 'home' }))setupNavigationTabSwitching()navigation handler, whento.typeisroute,stop, ortimetable: callbottomSheet?.open('half')(only fires on mobile sinceBottomSheetControlleris a no-op on desktop)Gotchas:
:checked ~ .tab-contentselectors. Only the visual appearance is suppressed withdisplay: none.dockis alreadyposition: fixed; bottom: 0; width: 100%— don't re-declare these.pb-[env(safe-area-inset-bottom)]on the dock requiresviewport-fit=coverin the viewport meta (added in this phase).close()calls, to avoid feedback loops.BottomSheetControllerconstructor still exits early on desktop (window.innerWidth >= 768), soopen()/close()calls fromindex.tsare safe to make unconditionally — they just do nothing on desktop.Original Issue
We have attempted mobile support through CURRENT_PLAN.md
There are many issues, so lets add a follow on plan #67b
First: Uncaught TypeError: crypto.randomUUID is not a function
Next, I want to use the daisyui Dock feature: https://daisyui.com/components/dock/ For the tabs on mobile. The bottom sheet should pop up on top of the dock.
Lets additionally change the ui state so that we do keep track of the tab that you're on, instead of before where we just kept track of the selected object. This means that when you switch to files or changes, you are no longer focussed on the object. This provides a cleaner state for both web and mobile.
One difference on mobile is the ability to be focused on nothing, so you'll just see the dock and no bottom sheet. When you click on browse, it will focus on the feed and open the feed in the bottom sheet. If you click on an object on the map, it will focus on that object and open that object in the bottom sheet. If you close the bottom sheet, the selection goes away. If you click on Files or Changes, they will open in the bottom sheet and the selection goes away.