Commit Graph

262 Commits

Author SHA1 Message Date
Maurice 73ac4b29ad feat(collections): filter by category on the phone (#2618)
The phone toolbar gets a category chip beside the status and label chips,
fed by the same categoryOptions the desktop dropdown uses, and no longer
clears a category picked on desktop. Managing labels moves into the label
panel so the row keeps four chips at phone width.
2026-11-13 10:17:10 +01:00
Maurice 8401428ca7 feat(pdf): bake place photos into the trip PDF at thumbnail size (#1501)
The print engine embedded every place photo at full resolution, so a trip of a
few hundred stops saved to a PDF of tens of megabytes. Same-origin photos are now
fetched six at a time, scaled to a 156 px short side and inlined as JPEG data
URLs; photos from other origins, failures and an aborted export keep the URL.
2026-11-13 10:17:06 +01:00
Maurice 12406bbbf4 feat(pdf): large text switch in the trip PDF preview (#2817)
A third switch next to the page break and transport notes switches scales the
day content's type by 1.35 and darkens its greys, for readers who print the
plan. Off by default and remembered per browser like the other two; the day
content's sizes and greys now come from three CSS variables on <body>.
2026-11-13 10:17:06 +01:00
Maurice 12ae32b69e feat(map): setting to hide the Mapbox basemap points of interest (#1761)
Mapbox Standard labels shops, restaurants and sights of its own; they look like trip
places but cannot be picked. A Hide Points of Interest switch next to the other Mapbox
options, on the desktop and the phone, turns them off on the trip map and the preview
without a rebuild. The Standard config handling moves into useStandardBasemapConfig.
2026-11-13 10:17:06 +01:00
Maurice 0eac3a9f49 feat(planner): fold the place inspector to its head and keep the place selected (#3039)
On a landscape phone or a small tablet the inspector covered most of the map, and the
only way to clear it was closing it, which deselected the place. A chevron in the head
now folds the card to the avatar and name; the next place opens in full. The head band
moves to PlaceInspectorHead so the inspector stays inside its size budget.
2026-11-13 10:17:05 +01:00
Maurice 72fc61a016 feat(costs): leave a category out of the totals for a look (#2819)
Seeing what a trip cost without, say, food meant adding it up by hand. A
click (or tap) on a category in the breakdown now leaves it out of the
total, your share and what you paid, dimmed in place with a line naming it
and Count all to undo. View only: nothing is saved, and what is owed, open
or settled stays whole. The desktop breakdown moves into its own component.
2026-11-13 10:17:03 +01:00
Maurice a70eea5bf2 feat(costs): let a trip keep its costs as totals only (#1714)
Travellers who track what a trip costs but never split it saw an
Unfinished warning on every expense and a settle-up they had no use for.
A trip now has a costs mode (appended migration, trips.costs_mode, split
by default); totals leaves payers, shares and settling up out of Costs on
desktop and phone through the same gate as a trip of one, and saves new
expenses without a payer. PUT /api/trips/:id and update_trip take it on
budget_edit. The split chips move into their own component.
2026-11-13 10:17:03 +01:00
Maurice c9c419b4ad feat(costs): leave out owing and settling on a trip of one (#2689)
With one traveler every share is the whole amount, yet Costs showed owe,
owed, outstanding, settle-up, balances and the final budget. A shared gate
(showsSplitting) now hides that side on desktop and phone, unless the ledger
still names someone else; the expense editor drops who paid and the split
while the expense holds nothing more. The payment dialog moves into its own
file to keep the panel under the size ratchet.
2026-11-13 10:17:03 +01:00
Maurice 6759277c3b feat(costs): link a trip file as an expense receipt (#2839)
A booking confirmation that is also the invoice had to be uploaded a second
time to sit on the expense. The expense editor (desktop and phone) now lists
the trip's files to link, the booking's own first; the save sends the id in
receipt_file_ids, which the server already links. The desktop receipts block
moves into its own component.
2026-11-13 10:17:02 +01:00
Maurice 2934319722 feat(costs): start a new expense in the trip currency (#2807)
A new expense opened in the display currency, so every bill on the road
needed the trip currency picked from the full list. It now starts in the
trip's own currency (a scanned receipt keeps the one it read), and the
trip and display currencies lead the picker on desktop and phone.
2026-11-13 10:17:02 +01:00
Maurice d4c81bc5f2 chore(lint): lower the warning baseline for the two promise rules the dock change cleared 2026-11-13 08:42:01 +01:00
Maurice 855bf8610a refactor(planner): the day plan's drag state lives in a hook of its own; the holiday provider cases get a suite of their own
DayPlanSidebar grew past its size baseline with the Firefox drag fix. Its drag state (what is dragged, the drop line, the day under the drag, whether a drag happened) and the effect that ends a lost drag move into useDayPlanDragState, typed, which also lowers the file's strict-mode count; size and strict baselines are lowered with it.

vacay.service.test.ts went past the 2000-line limit once the Nager v4 cases were back in it. They move into vacay.holiday-provider.test.ts, which takes VacayService from a Nest testing module over a snapshot db, so neither the db mock nor a hand-built service is needed.
2026-11-11 22:38:59 +00:00
Maurice 742edc4a79 fix(ci): today's changes pass the release gates
- iOS: the navigation proxy reports an error page through a callback the controller sets; it called the controller's method on itself and did not build.
- keyboard: the done key reads the field's text in the capture phase, before the field's own handler, so a list that adds an item on Enter and clears itself keeps the keyboard; the tests wire it as the app does.
- Ireland migration: the queued writes use addSql instead of awaiting inside loops; only table constants and integer ids reach the SQL.
- tests: the Dawarich GL test types its two layer specs once (strict baseline lowered), the collab test reads the id off the listed message, the reasoning test runs its four servers in parallel, and a wasm copy covers the precompressed branch without a charset.
- en wording: the deviations agreement no longer calls TREK self-hosted.
2026-11-11 22:06:50 +00:00
Sebastian Fischer ec78cfbdd0 feat(tours): find bakeries and groceries on the map and along a hike
A multi-day hike restocks on the way: bread in the morning, food for
lunch and supper every day or two. Neither could be searched for.

- Explore pill: new `bakery` and `supermarket` chips. `supermarket`
  already existed on the server (shop=supermarket|convenience) but no
  pill offered it; `bakery` is new (shop=bakery).
- Along the tour: `bakery` and `supermarket` are offered to a hike,
  after its existing kinds so a new hike still starts on the same three.
- TREK places index: `bakery` maps to food_and_drink>casual_eatery>bakery;
  `supermarket` is narrowed to grocery and convenience stores, since the
  whole food_and_beverage_store branch also brought tobacconists and
  wine shops. Both paths checked against a live answer of the index.
  As the more specific term, a bakery is no longer listed as a place to
  eat when only `food` is asked along a tour.
- Category guess: a bakery or grocer picked from the map was preselected
  as Bar/Cafe or Shopping even where the admin had made a Bakery or
  Groceries category. The guess now looks for such a category first, by
  name in the usual languages or by icon, and keeps the broad one when
  there is none. The category icon picker offers Croissant and
  ShoppingBasket, the icons the map chips use.
- Labels in every locale; MCP tool description names the new kinds.
2026-11-11 20:59:59 +00:00
John Jahn 04b1fb72bb perf(static): serve the hashed assets from Brotli copies written at build time
Every file under assets/ was compressed again on each download, at the low
level a request path can afford. They carry their content hash in the name
and never change, so the client build now writes a Brotli copy beside each
compressible one (postbuild, scripts/precompress.mjs) and production points
a browser that accepts Brotli at that copy before express.static serves it.

Measured on a production build of 5.1.2, fetching the 652 precached files
the way a service worker install does: 16.3 MB -> 13.9 MB on the wire and
about 1.0 s -> 0.2 s of server CPU per install. A client without Brotli, a
range request and a build without copies are served exactly as before.
2026-11-11 20:59:40 +00:00
Maurice 278871a31e chore(theme): the login's fixed light colours move with its code step into MfaCodeStep
The login card is a fixed light surface whose text colours are written out,
not tokens. Four of them moved with the two-factor step, so the baseline moves
them too: 58 to 54 for the page, 4 for the new component, the same total.
2026-11-10 10:23:53 +01:00
Maurice 6b086eaed5 refactor: the login's code step and the reservation row shapes get modules of their own
Both files had grown past their size limit with this round's fixes. The
two-factor step moves to pages/login/MfaCodeStep.tsx and the reservation row
types to reservation-rows.ts, re-exported from the repository, and both size
baselines come down to match.
2026-11-10 09:55:36 +01:00
Maurice ed0142be7d chore(client): list the client certificate card as a phone-only screen 2026-11-09 12:38:52 +01:00
Maurice ffa07b3d05 chore(i18n): two task keys are in use again, the unused baseline goes down 2026-11-09 10:25:47 +01:00
Maurice b529cf4e57 fix: the checks the layout and weight fixes broke: a quote in a test name, state set inside effects, the misused-promise baseline, and tests that render the converter before settings load 2026-11-08 19:44:50 +01:00
Maurice 26dc88181d fix: the file size, theme and reading direction ratchets the last push tipped; widget previews and watch screens run by hand only 2026-11-08 13:09:53 +01:00
Maurice a9af19f02a fix(mobile): the journal as a trip tab keeps its switch and menu in the shell's top row, like the tour tab 2026-11-08 12:34:41 +01:00
Maurice eafb30555c fix(mobile): the iPad's tour tab opens saved tours, keeps its switch in the top row, and a tap shows no tooltip 2026-11-08 11:43:45 +01:00
Maurice 5f4fb5dae7 feat(mobile): the tour editor as a tab of its own on an iPad and an unfolded foldable
On the wide and split size classes the touch shell no longer sends the tours tab back to the plan. It gets the desktop's tour editor, wired over the shell's own planner (useTripPlannerPageOf): on split the trip's tours and the editor share a pane beside the map, on wide the pane and the map take turns. A phone keeps its tours in the places browser.
2026-11-08 09:58:33 +01:00
Maurice 2851eb7afe feat(mobile): a Google Maps route is imported into a road trip day on an iPad and an unfolded Duo
The desktop's import dialog keeps its markup and moves its logic into
useGoogleRouteImport, unchanged: the link previewed, its stops in order with
the unresolved ones named, and the resolved ones appended to the day picked,
at least two, under one request id per opening and day. The large screens
get the same flow as a sheet, offered on the stage card under the track
offer to a member who may add places to days. The phone has no entry to it.
2026-11-08 02:57:43 +00:00
Maurice 21afe89b13 feat(mobile): a road trip day follows an imported track on an iPad and an unfolded Duo
The desktop's track dialog comes to the large screens as a sheet over the
planner's followTrack, the hook RoadtripTrackModal runs on: the trip's tracks
nearest to the day first, the drive fitted to the one picked with via points,
and those vias dropped again. The stage card offers it in the wide and split
size classes, to an editor of days, on a trip that holds a track, and names
the track the day follows. The phone and the folded Duo have no entry to it.
2026-11-08 02:42:37 +00:00
Maurice 060a43ba64 feat(mobile): the driving figures are a form on an iPad and an unfolded Duo
On the phone the road trip's driving figures stay a read-out, set at the
desktop. A large screen is that table, so in the wide and split size classes
the same sheet edits the two driving limits, the day's window and where it
ends, the vehicle with its range and fill, and what the route may avoid,
through the planner's saveRoadtripLimit, the desktop dialog's own save. A
range worked out from the vehicle's own figures stays read-only, as on the
desktop, and a reader without the right to edit days sees every field
disabled. The phone and the folded Duo are unchanged.
2026-11-08 02:37:26 +00:00
Maurice a7cc1b9e57 fix(mobile): the checks the large-screen merge left red
- The trip's segmented control writes its fit through a ref, not into the
  element held in state (react-hooks/immutability).
- The amount field of a payment uses the body type tier, which follows the
  text size setting, instead of a raw size.
- The form sheet tests wait the frame the edge fade now measures on, and read
  the wide variant from the size class the shell writes.
- The native dashes spec lists its locales through node:fs, so shared needs no
  vite types for it (knip).
- Baselines lowered where the fixes removed warnings: no-misused-promises,
  no-non-null-assertion in tests, the MSheet rtl entry.
2026-11-07 23:56:33 +01:00
Maurice 8955790f17 fix(mobile): the trip's screens on an iPad and an unfolded foldable, nothing cut or covered
- Top bar: the segmented control keeps to the room between the back button
  and the trailing button, draws its segments tighter and then scrolls with
  faded edges instead of covering the back button. On a wide window every
  list tab puts its primary pill in the middle and its round buttons at the
  trailing end, so the pill no longer jumps between tabs.
- Day strip: a chevron over the faded end pages the days along on a wide
  window, and the fade reaches further; the chips keep clear of it.
- Plan pane: the day card ends on the rail's bottom line beside the map (as
  tall as its day across the page), scrolls inside a frame and fades the
  rows at its edges. Addresses and the hotel chip end in an ellipsis instead
  of being cut mid-letter; the weather chip keeps its width.
- Map: in the dark theme the map beside the pane takes the dark basemap.
- Places: the All / Unplanned / Planned chips are never narrower than their
  names and scroll with a faded edge; on a short screen Places/Tours shares
  their row.
- Chat: the list fades out under the floating controls instead of cutting a
  bubble. Notes and to-do chip rows fade at their edges and New Note stays
  outside the scrolling chips.
- Costs: the balance amounts share a line, the settle-up action wraps to a
  line of its own, the totals stand under their labels.
- Bookings and transports: one column until two cards fit, titles take two
  lines with the type under them, the time cell is never cut and a range
  names its unit once.
- Files: the preview pane shows a type tile beside the name where no PDF can
  be drawn in place, its actions keep their labels on one line and wrap as a
  row, link labels are badges, and a tile that opens its file is no toggle.
- Polls get a fill that differs from card and track, packing filters are two
  segmented controls, empty checkboxes get an edge with 3:1 contrast, and the
  middle dots between values are gone.
2026-11-07 23:25:16 +01:00
Maurice 61d925f3dd fix(mobile): the chat watches its list once it exists, keeps its draft, and the desktop map opens as before
- useCollabChatData: the resize observer that keeps the chat at its newest
  message attaches when the list is drawn (after the messages load), not at
  mount when there is no list yet. The test renders the real list after load.
- MCollabTab: the chat stays mounted, hidden, while a board fills the page on
  its own, so leaving two panes with Notes picked keeps the half typed
  message and the scroll position. The links card hugs its links on a wide
  window instead of a page-high empty card.
- openingView: the floored opening zoom and the second fit for the map's own
  size apply only beside the pane in the touch shell; the desktop planner
  and the phone open at Leaflet's nearest level again.
2026-11-07 23:25:16 +01:00
Maurice bf00412863 fix(mobile): Arabic reads in its direction: arrows turn round, Latin names keep their ends, figures stay whole
In the touch shell the back, forward, disclosure, date-range and flow
arrows kept pointing right in Arabic, so Settle up showed the debt the
wrong way round and Vacay's year arrows pointed inward. The shell now
mirrors lucide's direction arrows in right-to-left languages; an icon
that names its own treatment keeps it, and the lightbox arrows stay on
their physical sides.

Latin user text in Arabic rows lost its beginning when cut and moved its
punctuation to the wrong end. Names, titles, addresses and file names take
their direction from their own text (dir=auto) and still line up with the
row; markdown paragraphs, chat messages, poll options and journal stories
are isolated; signed balances, amounts, sizes, rates and leg figures read
as one left-to-right run; URL fields read left to right. Name pairs joined
by an arrow isolate each name and point from the first to the second.

The hero progress and poll result bars fill from the start edge. Arabic
and Hebrew uppercase caption labels grow a step and take the muted ink,
and a todo's due date in a notification is written in the reader's
language instead of as YYYY-MM-DD.
2026-11-07 23:25:16 +01:00
Maurice 5346182807 fix(mobile): the rail, the docks and the top-level screens on a large screen
From the large-screen review (visual findings of the shell and the top-level
screens):

- Rail: 80px wide, one caption size for every name (no shrinking per item),
  balanced two-line names with every entry as tall as the tallest, short rail
  names where a language's word is too long (mobileNav.rail*, all locales),
  and near-opaque glass so a map's colours no longer smear through it.
- Rail head: always one 56px circle, so the entries never jump between pages:
  the create action, the screen's own action (the vacation calendar's
  year/editor switch moves there instead of floating over the days) or the
  quiet logo on settings and administration. It stays put while a short rail
  scrolls.
- Vacation calendar: weekday letters over each month on a wide window; the
  editor's mode switch sits at the foot with room kept for it.
- Docks: More is marked with a ring rather than the centre button's fill, the
  dock glass is denser, and lists fade out under the dock instead of showing
  in the gap below it.
- Dashboard: trip names get the card's width with the dates under them, the
  hero's facts wrap as whole chips, the filter chips scroll with a fade, the
  hero ends above the dock on a phone on its side and its buttons sit on a
  dark ground; the header bar stands in the content's column.
- Journeys: on a wide window the header is the same glass bar, in the column
  of the cards, and the other journeys' label starts with them.
- Notifications: the round chevron back button, in the list's column.
- Settings and administration share one frame and width. Admin's new-user
  action sits under the section list's title, the users card header wraps
  inside the card, stat labels ellipsize, role badges read in dark mode.
- Collections: one card per place with the status inside it, worded in a
  readable mix of its colour.
- Atlas and the journey map frame clear of the rail and the header; the
  journey's day bar sits on a glass plate, and a phone on its side gets
  smaller cards.
- Rail label tests rewritten for the new rule; FE-MOB-PANES-016 duplicate
  renumbered to 017.
2026-11-07 23:25:15 +01:00
Maurice 0b7cee0b0d feat(mobile): the trip's tabs, administration, collections and the journal use the large screen
On an iPad or an unfolded foldable the list screens kept one phone-wide
column in the middle of the page. They now lay out for the room they have:

- Transports, bookings, polls and tasks put their cards in a grid of as many
  phone-wide columns as the page holds (CardGrid), three on a 13" iPad on
  its side, two upright, one in a narrow Split View.
- Costs: with room for two panes (split size class) the summary (total,
  owe and owed, settle up, final budget, categories) stands in a pane of its
  own beside the expenses, each scrolling on its own (TabPanes). The search
  field sits in the expenses' column again instead of running past it.
- Files: a grid of tiles with each photo's picture; with room for two panes
  the picked file is previewed beside the grid with what it belongs to and
  its actions, the way Files on an iPad does. The signed preview address
  comes through fileRepo.previewUrl.
- Packing: the categories stand in columns, each card whole in its column;
  the action menu drops from its button at a popover's width.
- To-dos: the four smart filters as tiles and the trip's lists in a pane
  beside the tasks, which take the filter's name as their head.
- Collab: the chat stays in view at the trailing edge beside the notes,
  links or polls, and the header switches only the board. The chat keeps its
  place in the tree, so a fold or a rotation into two panes keeps the draft;
  a chat at its newest message stays there when its box changes size. Notes
  stand as a board in columns.
- Administration and settings share a section list beside the page
  (MSectionNav); the stats grid takes four columns.
- Collections: the lists stand in a column beside the places, which take two
  columns, and the head names the list on show.
- Journal: the entries become a feed beside the map, under their days, with
  photo, place and the start of the story, in step with the map like the
  strip of cards it replaces; it fades out under the header.
- The assistant opens as a tall panel at the trailing edge over a dimmed
  page, as Slide Over would, instead of covering the whole screen.
- The rail fits every name: a word too wide for it shrinks the label before
  it is hyphenated, and the admin entry uses its short name.
- The journeys and notifications headers keep to their column.
- The address screen of the native shell sets the photo as a panel beside
  the choices on a large screen on its side.

On a foldable that reports its fold, a leading pane ends at the fold and a
trailing one starts there. Phones keep their layout.
2026-11-07 23:25:12 +01:00
Maurice c204a25a9c feat(mobile): the touch shell laid out for iPad and unfolded foldables
The app shows the touch shell at every size now, an iPad's and an unfolded
foldable's included, instead of switching to the desktop pages from 768px.
One route tree survives rotation, Split View, Stage Manager and folding, and
the app's own features (Wallet, sharing into a trip, the edge swipe back)
are there on the big screen too.

Two size classes drive the layout (hooks/sizeClass.ts, Tailwind variants
wide: and split:):

- wide (600pt and taller than a phone on its side): a glass navigation rail
  on the leading edge replaces the dock and holds every destination with its
  name; sheets become centred form sheets; the trip's More menu is a popover
  beside the rail; lists keep a readable measure; dashboard, journey and
  vacay get columns; full-bleed maps run under the floating rail.
- split (900pt): the trip's plan, places or road trip chain sit in a pane
  beside the map, which follows the plan's day; the list/map switch hides
  and shows the pane like a sidebar; on a foldable that reports its fold the
  pane ends at the fold. Settings show their sections beside the page and the
  dashboard keeps its widgets in a column of their own.

A hardware keyboard gets the shortcuts an iPad app has (⌘1 to ⌘9 for the
sections, ⌘N, ⌘, , ⌥←/⌥→ through the days, ⌃⌘S for the pane, ⌘[ back),
answered by the page or, with a binary that has the keyCommands feature,
handed to it as native key commands.

The day strip fades at an edge that runs on, journey cards grow on a wide
window and a card without a photo takes the day's colour, and the Leaflet
map measures itself again when its box changes size.
2026-11-07 23:25:12 +01:00
Maurice 1e4f1922e8 feat(android): bring the Android app level with the iOS app
Everything the iOS shell gained, built natively for Android 16 with Material
You, and back to Android 7:

- Home-screen widgets in Jetpack Glance: trip, today, bookings, to-dos,
  packing, world map and travel group, from the same snapshot the iOS widgets
  read. Wallpaper colours on Android 12+, resizable in three layouts, a trip
  picker per widget (reconfigurable), live previews in Android 15's picker
  and preview images before it.
- The travel day as a Live Update: a promoted ongoing notification with the
  next stop as the status-bar chip, a countdown and the day's stops as
  segments (ProgressStyle), a quiet ongoing notification before Android 16.
- A share sheet of its own: a Material bottom sheet with the trip picker for
  files, mails, pages and links shared from any app, and the coming trips as
  launcher and direct-share shortcuts.
- Push: channels per kind of notification (chat, trip updates, invitations,
  general) by the event the server now names, stacked per channel.
- Location for navigator.geolocation from the fused provider, a store for
  Mapbox's map resources (30 days, 250 MB), Google Play Billing behind the
  StoreKit methods, and Google Wallet save links.
- Large screens: every orientation and window size without a restart,
  the window's size classes and a foldable's posture and hinge for the UI
  (windowLayout), the UI's keyboard shortcuts as the app's (keyCommands),
  predictive back, per-app language.
- The native strings in the 28 languages of the iOS app, generated from its
  strings files (scripts/generate-android-strings.mjs).

Debug builds carry a widget gallery that draws every widget at every size.
2026-11-07 14:16:04 +01:00
Maurice 37a4e84360 feat: Apple Wallet passes for bookings
"Add to Apple Wallet" on a booking in the iOS app turns it into a TREK pass:
a boarding pass from and to for flights, trains, buses and boats, check-in and
check-out for a stay, pickup and drop-off for a car, the time for anything
else, with the confirmation code as a QR code. Wallet brings it up on the lock
screen around its time and place: times carry the offset of the endpoint's zone
(looked up from the coordinates where the endpoint has none), stays and
restaurants their place's coordinates. The labels come from the booking forms'
own strings, so nothing new to translate on the pass.

Only liketrek holds the Pass Type ID certificate, so the server sends the pass's
texts to the TREK services' signer (TREK_WALLET_PASS_URL, push.liketrek.com)
once per tap; it stores nothing, and TREK_SERVICES=off turns it off with the
other services. Texts are cleaned of links and shortened here, the answer must
be a .pkpass within 512 KB, and a user gets 20 passes a minute.

- New wallet-pass domain: GET /api/trips/:tripId/reservations/:id/wallet-pass
  behind the trip guard, the booking checked to belong to the trip; trip title
  and place come from the reservations domain (findPassContext)
- MWalletButton in the transport and booking sheets, only where the app binary
  has the wallet feature; undated bookings and failures are told apart
- TREK_WALLET_PASS_URL in .env.example, compose, Helm and the wiki
2026-11-07 11:25:19 +01:00
Maurice 19ef38a377 fix(demo): the phone welcome scales with the text size and is paired with the desktop one
MDemoWelcome used raw rem sizes, which ignore the text size setting and broke
theme:lint, and was missing from feature-pairs.json, which broke lint:pairs.
2026-11-07 10:05:23 +01:00
Maurice 8f3a8bd670 fix(ci): the carousel tests at the 90 ms settle, the search type, the hook back under its line limit
- The carousel and timeline tests step by the new 90 ms settle
- The journey search keeps its suggestion type through the fallback
- nearestCardIndex leaves useJourneyCarouselSync, which had grown past its
  line limit; WidgetBag is not exported; the test baseline drops by the
  non-null assertions a test no longer needs
2026-11-06 22:51:15 +01:00
Maurice b7951baf23 fix(ci): green the dev gates after the native and popup rounds
- RTL: the measured pills and centred controls use logical forms or a marked line
- i18n: the two native widget numbers are positions, not counts (NOT_PLURAL)
- Types: styleOverride on the lazy GL map, the location and shared-file payloads,
  the capabilities fallback, the transport sheet's stay metadata
- ESLint: latest-value refs move to layout effects, usePresence keeps the last
  open state in state, the booking import opens clean with a shared document
  kept in the list (the reset effect used to clear it again)
- Layers: the phone import sheet lives under mobile/ and reads through tripRepo;
  the offline host check moves to utils/tileUrl
- Sizes: plugin layer geometry, hardNavigate and the exit animations get
  modules of their own
- Tests follow the status radios, the stay chip overview, the dock + button
  for the first list and the field token; store registry lists the new stores
2026-11-06 18:24:25 +01:00
Maurice b317877c41 feat(mobile): remaining sheets get the common header
Atlas bucket list, open route in, open in TREK, the place actions and the
MCP/OAuth client sheets now show the icon tile header (or, where a sheet
closes only by its buttons, the same title row without the close).
2026-11-06 16:48:25 +01:00
Maurice 27c19b5ff5 feat(mobile): admin, settings picker and place sheets in the common style, all sheets on glass
Admin sheets: their frame draws the icon tile header (an icon per sheet, the
plugin sheets' icons moved out of the title into the tile), the soft scroll
edge and 42 px footer buttons; admin fields use the sheets' eyebrow labels
and round inputs. The settings picker, the bulk category sheet and the save
to list sheet get the common header (TileHeader may now leave out the icon
for a plain picker). Every phone sheet now uses the glass material, as the
trip settings do; it stays 94 % opaque, so forms over the map remain
legible.
2026-11-06 16:45:09 +01:00
Maurice ffd848e5dc feat(mobile): confirm dialogs and Vacay sheets in the common sheet style
The shared confirm sheet (44 places) gets the icon tile with the title, a
warning icon for destructive questions, and the sheets' 42 px buttons with
the danger colour on a destructive confirm. The dashboard's and the
collections' own confirm dialogs now use it.

Vacay invite, shared calendars and settings get the icon tile header; the
settings' rows separated by hairlines become cards on the inner surface, as
the trip settings' sections.
2026-11-06 16:40:06 +01:00
Maurice 45361c276c feat(mobile): journey create and entry sheets in the common sheet style
Both get the icon tile header (the entry keeps its move buttons between
title and close), glass, the soft scroll edge and the sheets' 42 px footer
buttons; the journey name is a round field, delete in the entry's footer a
round icon button. The collection share sheet's invite button is round like
the trip settings' one.
2026-11-06 16:34:44 +01:00
Maurice 1b24e3dcef feat(mobile): collections sheets in the common sheet style
The collections sheets had a header of their own with a hairline, white
square fields and short buttons. Their kit now draws the icon tile header
every phone sheet has (an icon per sheet), round 42 px fields on the field
surface and 42 px footer buttons; the sheets sit on glass with the soft
scroll edge. New list and add place lose their last own field styles: the
labels are the sheets' eyebrows, the search fields, the category picker and
the status choices are round fields of the same height.
2026-11-06 16:32:37 +01:00
Maurice 2aa25e3fe7 fix(mobile): a tour opens in a sheet instead of the desktop dialog
A tour tapped in the plan opened the desktop detail dialog in a hand-built
overlay: no slide, no drag to close, the desktop's frame on a phone. The
dialog now renders into the frame it is given; on the phone that is a sheet
like every other detail (MTourDetailShell), with the tour's name as its
title, its whole content and every action, the back gesture and an exit
animation.
2026-11-06 16:22:23 +01:00
Maurice ec87f280c3 feat(mobile): journey settings in the trip settings' style
The journey settings sheet looked like a different app next to the trip
settings. It now uses the same parts: the glass card with the icon tile
header and the journey's name under the title, sections as inner cards with
a title, count badge and hint, 42 px round fields and buttons, the shared
link field, and switch rows for tracks, entry fields and the public link.
Those parts (SheetSection and the SHEET_* button and field classes) moved
into MTripSheetUi for every sheet to use.

Fields and buttons sitting directly in a column no longer shrink below
their height; name, subtitle and the archive button were squeezed flat.
2026-11-06 16:07:57 +01:00
Maurice 6e362de3da fix(mobile): collections start their first list from the dock, settings sheets aligned
Collections: the empty screen's own New list button is gone; the dock's +
starts the first list while there is none and adds places once there is one.

Trip settings: counts sit in a badge next to the section title instead of
reading as part of it (ACCESS 1), and every round button of the sheet,
invite and add guest as well as the member and guest actions, is one 42 px
circle; the icon-only buttons were wider than tall.

Journey settings: the public link is the same field as the trip's share and
invite links, through one shared MLinkField; the shared map's extras hang
under the map row with a guide line and smaller labels; removing the link is
a full-size button.
2026-11-06 16:01:28 +01:00
Maurice 821f23aed4 fix(mobile): compact place details, softer sheet edges, icon buttons for copy and share
Add place on the phone: the place details showed the mascot half a screen
high while nothing was picked or nothing was found, and pushed the name field
below the fold. Both states are now one quiet line, as in the desktop dialog,
and the details sit in a card in the mobile tokens.

Sheets with a header over a scroll box (trip settings, day, export,
transport, files and more) cut their content off in a hard line right under
the header icon. The scroll box now keeps a little room under the header and
fades its content out at the edges.

Copy and share next to a share or invite link are round icon buttons of the
same size; the share button showed no icon because the copy button's padding
left it no room.
2026-11-06 15:44:07 +01:00
Maurice 6835fd7bf3 feat(mobile): page transitions, pull-to-refresh, share sheet and haptics
Page transitions: on the phone, pages move like a native navigation stack,
built on the View Transitions API (mobile/routeTransition.ts). A page opened
from another slides in from the trailing edge, back slides it away, and
switching between the dock's sections cross-fades while the dock stands
still. Lazy routes do not flash their skeleton: the swap waits, behind the
frozen snapshot, until the new page rendered. The edge-swipe back gesture
already moves the page and skips the transition. RTL mirrors the motion,
reduced motion and desktop get none.

Pull-to-refresh on the mobile dashboard: the page follows the finger with
resistance, ticks once past the threshold and re-reads trips and
notifications quietly, without a loading state.

Share: trip share and invite links and the journey link get a share button
next to copy, opening the system share sheet (Capacitor Share in the apps,
Web Share in browsers that have it).

Haptics: a selection click for switches and segmented controls, a tick when
a sheet is flung closed, and a firmer bump for the chat's long press.

Theme lint: this branch's new screens use the type and z-index tokens, the
Vacay company tint is a token, and the baseline is lowered to the new
counts.
2026-11-06 15:02:55 +01:00
Maurice 4c0583845a fix(map): keep the selected place findable on the map
Selecting a place no longer spiderfies a city-sized cluster: the reveal
only fans open bubbles of up to 12 stops, or stacks whose stops all share
one coordinate, so a zoomed-out trip with hundreds of places stays usable
(#2990).

The selected pin now carries a white border inside a pulsing blue ring on
both renderers (static under reduced motion), and the map measures the
place card instead of assuming a fixed 320px, so the selection pans the
pin above even a tall card on portrait tablets and eases it back out when
the card grows over it later (#2991).

Closes #2990
Closes #2991
2026-11-06 12:50:02 +01:00