From 9f0fe456a4b39b46164d29653336a36e1a28d6c3 Mon Sep 17 00:00:00 2001 From: Maurice Date: Thu, 1 Oct 2026 10:04:18 +0200 Subject: [PATCH] feat(planner): the panel widths can be dragged with a finger, also on a tablet The handles on the day plan and the places panel only listened to the mouse, so on an iPad they did nothing, and in the portrait band they were left out. They now follow a finger as well, show a grip on touch screens, keep the page and the map from taking the gesture, and stay in the narrow layout within the room the map needs. As separators they also move with the arrow keys. (#1012) --- .../components/Planner/PanelResizeHandle.tsx | 51 +++++++++++++++++++ client/src/hooks/useResizablePanels.ts | 50 +++++++++++++----- client/src/pages/TripPlannerPage.tsx | 23 +++------ .../src/pages/TripPlannerPage.wiring.test.tsx | 31 +++++++++-- .../src/pages/tripPlanner/useTripPlanner.ts | 4 +- .../hooks/useResizablePanels.test.ts | 42 +++++++++++++++ shared/src/i18n/ar/trip.ts | 1 + shared/src/i18n/az/trip.ts | 1 + shared/src/i18n/br/trip.ts | 1 + shared/src/i18n/ca/trip.ts | 1 + shared/src/i18n/cs/trip.ts | 1 + shared/src/i18n/de/trip.ts | 1 + shared/src/i18n/en/trip.ts | 1 + shared/src/i18n/es/trip.ts | 1 + shared/src/i18n/et/trip.ts | 1 + shared/src/i18n/fr/trip.ts | 1 + shared/src/i18n/gr/trip.ts | 1 + shared/src/i18n/hu/trip.ts | 1 + shared/src/i18n/id/trip.ts | 1 + shared/src/i18n/it/trip.ts | 1 + shared/src/i18n/ja/trip.ts | 1 + shared/src/i18n/ko/trip.ts | 1 + shared/src/i18n/nl/trip.ts | 1 + shared/src/i18n/pl/trip.ts | 1 + shared/src/i18n/ru/trip.ts | 1 + shared/src/i18n/sk/trip.ts | 1 + shared/src/i18n/sv/trip.ts | 1 + shared/src/i18n/th/trip.ts | 1 + shared/src/i18n/tr/trip.ts | 1 + shared/src/i18n/uk/trip.ts | 1 + shared/src/i18n/vi/trip.ts | 1 + shared/src/i18n/zh-TW/trip.ts | 1 + shared/src/i18n/zh/trip.ts | 1 + 33 files changed, 193 insertions(+), 35 deletions(-) create mode 100644 client/src/components/Planner/PanelResizeHandle.tsx diff --git a/client/src/components/Planner/PanelResizeHandle.tsx b/client/src/components/Planner/PanelResizeHandle.tsx new file mode 100644 index 000000000..62212d4b3 --- /dev/null +++ b/client/src/components/Planner/PanelResizeHandle.tsx @@ -0,0 +1,51 @@ +import type { KeyboardEvent } from 'react' +import { useTranslation } from '../../i18n' + +const STEP = 16 + +interface PanelResizeHandleProps { + /** The panel this handle sits on: 'left' grows to the right, 'right' to the left. */ + side: 'left' | 'right' + width: number + min: number + max: number + onStart: () => void + onNudge: (delta: number) => void +} + +/** + * The grip on a planner panel's inner edge (#1012). A mouse drags it, a finger on + * a tablet drags it (touch-action: none keeps the page and the map from taking + * the gesture), and the arrow keys move it, since it is a separator a keyboard + * can reach. On a touch screen the grip shows; with a mouse it lights on hover. + */ +export default function PanelResizeHandle({ side, width, min, max, onStart, onNudge }: PanelResizeHandleProps) { + const { t } = useTranslation() + const onKeyDown = (e: KeyboardEvent) => { + const grow = side === 'left' ? 'ArrowRight' : 'ArrowLeft' + const shrink = side === 'left' ? 'ArrowLeft' : 'ArrowRight' + if (e.key !== grow && e.key !== shrink) return + e.preventDefault() + onNudge(e.key === grow ? STEP : -STEP) + } + return ( +
+ + +
+ ) +} diff --git a/client/src/hooks/useResizablePanels.ts b/client/src/hooks/useResizablePanels.ts index ad0060b1b..8b3a81beb 100644 --- a/client/src/hooks/useResizablePanels.ts +++ b/client/src/hooks/useResizablePanels.ts @@ -12,6 +12,16 @@ const NARROW_QUERY = '(min-width: 768px) and (max-width: 1023px)' /** However wide a panel was dragged on a big screen, the map keeps this much. */ const MIN_MAP = 360 +function clampWidth(w: number, max: number = MAX_SIDEBAR): number { + return Math.max(MIN_SIDEBAR, Math.min(max, w)) +} + +/** Stores a dragged width and hands it back; a blocked storage only costs the memory of it. */ +function remember(key: string, w: number): number { + try { localStorage.setItem(key, String(w)) } catch { /* not remembered, still applied */ } + return w +} + export function useResizablePanels() { const [leftWidth, setLeftWidth] = useState(() => Number.parseInt(localStorage.getItem('sidebarLeftWidth') || '') || 340) const [rightWidth, setRightWidth] = useState(() => Number.parseInt(localStorage.getItem('sidebarRightWidth') || '') || 300) @@ -48,18 +58,21 @@ export function useResizablePanels() { return () => window.removeEventListener('resize', measure) }, [narrow]) + // A mouse drags through mousemove; a finger on a tablet sends touch events and + // never a mousemove, which is why the handles used to be dead on an iPad (#1012). useEffect(() => { - const onMove = (e: MouseEvent) => { - if (isResizingLeft.current) { - const w = Math.max(MIN_SIDEBAR, Math.min(MAX_SIDEBAR, e.clientX - 10)) - setLeftWidth(w) - localStorage.setItem('sidebarLeftWidth', String(w)) - } - if (isResizingRight.current) { - const w = Math.max(MIN_SIDEBAR, Math.min(MAX_SIDEBAR, window.innerWidth - e.clientX - 10)) - setRightWidth(w) - localStorage.setItem('sidebarRightWidth', String(w)) - } + const moveTo = (clientX: number) => { + if (isResizingLeft.current) setLeftWidth(remember('sidebarLeftWidth', clampWidth(clientX - 10))) + if (isResizingRight.current) setRightWidth(remember('sidebarRightWidth', clampWidth(window.innerWidth - clientX - 10))) + } + const onMove = (e: MouseEvent) => moveTo(e.clientX) + const onTouchMove = (e: TouchEvent) => { + if (!isResizingLeft.current && !isResizingRight.current) return + const touch = e.touches[0] + if (!touch) return + // The drag owns the finger: no page scroll and no map pan underneath it. + e.preventDefault() + moveTo(touch.clientX) } const onUp = () => { isResizingLeft.current = false @@ -69,15 +82,27 @@ export function useResizablePanels() { } document.addEventListener('mousemove', onMove) document.addEventListener('mouseup', onUp) + document.addEventListener('touchmove', onTouchMove, { passive: false }) + document.addEventListener('touchend', onUp) + document.addEventListener('touchcancel', onUp) return () => { document.removeEventListener('mousemove', onMove) document.removeEventListener('mouseup', onUp) + document.removeEventListener('touchmove', onTouchMove) + document.removeEventListener('touchend', onUp) + document.removeEventListener('touchcancel', onUp) } }, []) const startResizeLeft = () => { isResizingLeft.current = true; document.body.style.cursor = 'col-resize'; document.body.style.userSelect = 'none' } const startResizeRight = () => { isResizingRight.current = true; document.body.style.cursor = 'col-resize'; document.body.style.userSelect = 'none' } + // The handles are separators a keyboard can move too: an arrow key grows or + // shrinks the panel by a step, from the width it shows right now. + const resizeMax = Math.max(MIN_SIDEBAR, Math.min(MAX_SIDEBAR, maxPanel)) + const nudgeLeft = (delta: number) => setLeftWidth(remember('sidebarLeftWidth', clampWidth(Math.min(leftWidth, maxPanel) + delta, resizeMax))) + const nudgeRight = (delta: number) => setRightWidth(remember('sidebarRightWidth', clampWidth(Math.min(rightWidth, maxPanel) + delta, resizeMax))) + // What the layout actually shows. The collapse flags stay the caller's intent — // handlePlaceClick reopening "both" must not re-crowd a narrow screen. const leftHidden = narrow ? narrowPanel !== 'left' : leftCollapsed @@ -99,6 +124,7 @@ export function useResizablePanels() { rightWidth: Math.min(rightWidth, maxPanel), leftCollapsed, rightCollapsed, setLeftCollapsed, setRightCollapsed, leftHidden, rightHidden, toggleLeft, toggleRight, narrow, - startResizeLeft, startResizeRight, + startResizeLeft, startResizeRight, nudgeLeft, nudgeRight, + resizeMin: MIN_SIDEBAR, resizeMax, } } diff --git a/client/src/pages/TripPlannerPage.tsx b/client/src/pages/TripPlannerPage.tsx index 21062c03c..542d5c541 100644 --- a/client/src/pages/TripPlannerPage.tsx +++ b/client/src/pages/TripPlannerPage.tsx @@ -58,6 +58,7 @@ import { usePoiExplore } from '../components/Map/usePoiExplore' import { useMergedMapPois } from '../components/Map/useMergedMapPois' import PoiCategoryPill from '../components/Map/PoiCategoryPill' import { useTouchDragBridge } from '../hooks/useTouchDragBridge' +import PanelResizeHandle from '../components/Planner/PanelResizeHandle' // The tab panels are the planner's dead weight: each one mounts only while its // own tab is active, so the page chunk carried code most sessions never run. They @@ -285,8 +286,8 @@ function TripPlannerPageDesktop(): React.ReactElement | null { allowedFileTypes, tripMembers, setTripMembers, refreshMembers, loadAccommodations, TRANSPORT_TYPES, TRIP_TABS, activeTab, setActiveTab, handleTabChange, leftWidth, rightWidth, - leftHidden, rightHidden, toggleLeft, toggleRight, narrowPanels, - startResizeLeft, startResizeRight, + leftHidden, rightHidden, toggleLeft, toggleRight, + startResizeLeft, startResizeRight, nudgeLeft, nudgeRight, resizeMin, resizeMax, selectedPlaceId, selectedAssignmentId, setSelectedPlaceId, selectAssignment, showDayDetail, setShowDayDetail, dayDetailCollapsed, setDayDetailCollapsed, stayPickerDayId, setStayPickerDayId, @@ -741,13 +742,8 @@ function TripPlannerPageDesktop(): React.ReactElement | null { onCreatePlaceForDay={can('place_edit', trip) ? (dayId) => { setEditingPlace(null); setPlaceFormDayId(dayId); setShowPlaceForm(true) } : undefined} /> )} - {!leftHidden && !narrowPanels && ( -
+ {!leftHidden && ( + )}
@@ -781,13 +777,8 @@ function TripPlannerPageDesktop(): React.ReactElement | null { transition: 'width 0.25s ease', opacity: rightHidden ? 0 : 1, }}> - {!rightHidden && !narrowPanels && ( -
+ {!rightHidden && ( + )}
{roadtripActive ? ( diff --git a/client/src/pages/TripPlannerPage.wiring.test.tsx b/client/src/pages/TripPlannerPage.wiring.test.tsx index 83cffa95d..2ad9f9516 100644 --- a/client/src/pages/TripPlannerPage.wiring.test.tsx +++ b/client/src/pages/TripPlannerPage.wiring.test.tsx @@ -227,6 +227,10 @@ function baseState(): HookState { narrowPanels: false, startResizeLeft: vi.fn(), startResizeRight: vi.fn(), + nudgeLeft: vi.fn(), + nudgeRight: vi.fn(), + resizeMin: 200, + resizeMax: 520, selectedPlaceId: null, selectedAssignmentId: null, setSelectedPlaceId: vi.fn(), @@ -578,11 +582,28 @@ describe('TripPlannerPage — plan tab', () => { expect(screen.getByTestId('day-plan-sidebar')).toBeInTheDocument() }) - // Mouse-only handles (mousedown + document mousemove) are inert on a tablet, and - // a 4px invisible strip on the panel edge is a trap for a fat finger (#2247). - it('FE-PAGE-TPW-015b: the narrow layout drops the mouse-only resize handles', () => { - const { container } = renderPage({ narrowPanels: true }) - expect(container.querySelectorAll('div[style*="col-resize"]')).toHaveLength(0) + // The handles take a finger now, with a visible grip on touch screens, so the + // tablet band keeps the one it shows (#1012); before, a 4px mouse-only strip there + // was a trap for a fat finger (#2247). + it('FE-PAGE-TPW-015b: the narrow layout keeps a touch-ready handle on the panel it shows', () => { + const { container } = renderPage({ narrowPanels: true, rightHidden: true }) + const handles = container.querySelectorAll('div[role="separator"]') + expect(handles).toHaveLength(1) + expect(handles[0].style.touchAction).toBe('none') + fireEvent.touchStart(handles[0]) + expect(hookState.startResizeLeft).toHaveBeenCalled() + }) + + it('FE-PAGE-TPW-015c: the arrow keys move a handle like a separator (#1012)', () => { + const { container } = renderPage() + const [left, right] = container.querySelectorAll('div[role="separator"]') + expect(left).toHaveAttribute('aria-valuenow') + fireEvent.keyDown(left, { key: 'ArrowRight' }) + expect(hookState.nudgeLeft).toHaveBeenCalledWith(16) + fireEvent.keyDown(right, { key: 'ArrowLeft' }) + expect(hookState.nudgeRight).toHaveBeenCalledWith(16) + fireEvent.keyDown(right, { key: 'ArrowRight' }) + expect(hookState.nudgeRight).toHaveBeenCalledWith(-16) }) it('FE-PAGE-TPW-015: the resize handles start a drag on mouse-down and highlight on hover', () => { diff --git a/client/src/pages/tripPlanner/useTripPlanner.ts b/client/src/pages/tripPlanner/useTripPlanner.ts index 20113d9ce..2e8f8c7d1 100644 --- a/client/src/pages/tripPlanner/useTripPlanner.ts +++ b/client/src/pages/tripPlanner/useTripPlanner.ts @@ -310,7 +310,7 @@ export function useTripPlanner() { const { leftWidth, rightWidth, leftCollapsed, rightCollapsed, setLeftCollapsed, setRightCollapsed, leftHidden, rightHidden, toggleLeft, toggleRight, narrow: narrowPanels, - startResizeLeft, startResizeRight, + startResizeLeft, startResizeRight, nudgeLeft, nudgeRight, resizeMin, resizeMax, } = useResizablePanels() const { selectedPlaceId, selectedAssignmentId, setSelectedPlaceId, selectAssignment } = usePlaceSelection() const [dayDetail, setShowDayDetail] = useState(null) @@ -2957,7 +2957,7 @@ export function useTripPlanner() { TRANSPORT_TYPES, TRIP_TABS, activeTab, setActiveTab, handleTabChange, leftWidth, rightWidth, leftCollapsed, rightCollapsed, setLeftCollapsed, setRightCollapsed, leftHidden, rightHidden, toggleLeft, toggleRight, narrowPanels, - startResizeLeft, startResizeRight, + startResizeLeft, startResizeRight, nudgeLeft, nudgeRight, resizeMin, resizeMax, selectedPlaceId, selectedAssignmentId, setSelectedPlaceId, selectAssignment, showDayDetail, setShowDayDetail, dayDetailCollapsed, setDayDetailCollapsed, stayPickerDayId, setStayPickerDayId, diff --git a/client/tests/integration/hooks/useResizablePanels.test.ts b/client/tests/integration/hooks/useResizablePanels.test.ts index 89b1064f2..989afbfa4 100644 --- a/client/tests/integration/hooks/useResizablePanels.test.ts +++ b/client/tests/integration/hooks/useResizablePanels.test.ts @@ -162,6 +162,48 @@ describe('useResizablePanels', () => { expect(result.current.rightWidth).toBe(initialRight); }); + it('FE-HOOK-PANELS-011b: a finger drags the left panel on a tablet, and lifting it ends the drag (#1012)', () => { + const { result } = renderHook(() => useResizablePanels()); + + act(() => { + result.current.startResizeLeft(); + }); + act(() => { + fireEvent.touchMove(document, { touches: [{ clientX: 410 }] }); + }); + expect(result.current.leftWidth).toBe(400); + expect(localStorage.getItem('sidebarLeftWidth')).toBe('400'); + + act(() => { + fireEvent.touchEnd(document); + }); + act(() => { + fireEvent.touchMove(document, { touches: [{ clientX: 300 }] }); + }); + expect(result.current.leftWidth).toBe(400); + expect(document.body.style.cursor).toBe(''); + }); + + it('FE-HOOK-PANELS-011c: the keyboard nudges a panel within its bounds (#1012)', () => { + const { result } = renderHook(() => useResizablePanels()); + const start = result.current.leftWidth; + + act(() => { + result.current.nudgeLeft(16); + }); + expect(result.current.leftWidth).toBe(start + 16); + + act(() => { + result.current.nudgeLeft(-10_000); + }); + expect(result.current.leftWidth).toBe(result.current.resizeMin); + + act(() => { + result.current.nudgeRight(10_000); + }); + expect(result.current.rightWidth).toBe(result.current.resizeMax); + }); + it('FE-HOOK-PANELS-012: body userSelect set to none during resize, cleared on mouseup', () => { const { result } = renderHook(() => useResizablePanels()); diff --git a/shared/src/i18n/ar/trip.ts b/shared/src/i18n/ar/trip.ts index 14e259a53..90f90e345 100644 --- a/shared/src/i18n/ar/trip.ts +++ b/shared/src/i18n/ar/trip.ts @@ -18,6 +18,7 @@ const trip: TranslationStrings = { 'trip.loadingSteps.arrive': 'أوشكنا على الوصول...', 'trip.mobilePlan': 'الخطة', 'trip.mobilePlaces': 'الأماكن', + 'trip.panelWidth': 'عرض اللوحة', 'trip.toast.placeUpdated': 'تم تحديث المكان', 'trip.toast.tripUpdated': 'تم تحديث الرحلة', 'trip.toast.placeAdded': 'تمت إضافة المكان', diff --git a/shared/src/i18n/az/trip.ts b/shared/src/i18n/az/trip.ts index b4784c964..2556600e7 100644 --- a/shared/src/i18n/az/trip.ts +++ b/shared/src/i18n/az/trip.ts @@ -20,6 +20,7 @@ const trip: TranslationStrings = { 'trip.mobilePlan': 'Plan', 'trip.mobilePlaces': 'Məkanlar', + 'trip.panelWidth': 'Panelin eni', 'trip.toast.placeUpdated': 'Məkan yeniləndi', 'trip.toast.tripUpdated': 'Səyahət yeniləndi', diff --git a/shared/src/i18n/br/trip.ts b/shared/src/i18n/br/trip.ts index b0375ba75..ba1d44001 100644 --- a/shared/src/i18n/br/trip.ts +++ b/shared/src/i18n/br/trip.ts @@ -14,6 +14,7 @@ const trip: TranslationStrings = { 'trip.loading': 'Carregando viagem...', 'trip.mobilePlan': 'Plano', 'trip.mobilePlaces': 'Lugares', + 'trip.panelWidth': 'Largura do painel', 'trip.toast.placeUpdated': 'Lugar atualizado', 'trip.toast.tripUpdated': 'Viagem atualizada', 'trip.toast.placeAdded': 'Lugar adicionado', diff --git a/shared/src/i18n/ca/trip.ts b/shared/src/i18n/ca/trip.ts index 305fe75a9..a48acb08e 100644 --- a/shared/src/i18n/ca/trip.ts +++ b/shared/src/i18n/ca/trip.ts @@ -15,6 +15,7 @@ const trip: TranslationStrings = { 'trip.loadingPhotos': 'Carregant les fotos del lloc...', 'trip.mobilePlan': 'Planificació', 'trip.mobilePlaces': 'Llocs', + 'trip.panelWidth': 'Amplada del tauler', 'trip.toast.placeUpdated': 'Lloc actualitzat', 'trip.toast.placeAdded': 'Lloc afegit', 'trip.toast.placeDeleted': 'Lloc eliminat', diff --git a/shared/src/i18n/cs/trip.ts b/shared/src/i18n/cs/trip.ts index 812c36dde..3fad121a5 100644 --- a/shared/src/i18n/cs/trip.ts +++ b/shared/src/i18n/cs/trip.ts @@ -18,6 +18,7 @@ const trip: TranslationStrings = { 'trip.loadingSteps.arrive': 'Už jsme skoro tam...', 'trip.mobilePlan': 'Plán', 'trip.mobilePlaces': 'Místa', + 'trip.panelWidth': 'Šířka panelu', 'trip.toast.placeUpdated': 'Místo bylo aktualizováno', 'trip.toast.tripUpdated': 'Cesta aktualizována', 'trip.toast.placeAdded': 'Místo bylo přidáno', diff --git a/shared/src/i18n/de/trip.ts b/shared/src/i18n/de/trip.ts index fbd0d261b..52b4a813e 100644 --- a/shared/src/i18n/de/trip.ts +++ b/shared/src/i18n/de/trip.ts @@ -18,6 +18,7 @@ const trip: TranslationStrings = { 'trip.loadingSteps.arrive': 'Fast am Ziel...', 'trip.mobilePlan': 'Planung', 'trip.mobilePlaces': 'Orte', + 'trip.panelWidth': 'Breite des Bereichs', 'trip.toast.placeUpdated': 'Ort aktualisiert', 'trip.toast.tripUpdated': 'Reise aktualisiert', 'trip.toast.placeAdded': 'Ort hinzugefügt', diff --git a/shared/src/i18n/en/trip.ts b/shared/src/i18n/en/trip.ts index 3839481fa..d4da4a0aa 100644 --- a/shared/src/i18n/en/trip.ts +++ b/shared/src/i18n/en/trip.ts @@ -18,6 +18,7 @@ const trip: TranslationStrings = { 'trip.loadingSteps.arrive': 'Almost there...', 'trip.mobilePlan': 'Plan', 'trip.mobilePlaces': 'Places', + 'trip.panelWidth': 'Panel width', 'trip.toast.placeUpdated': 'Place updated', 'trip.toast.tripUpdated': 'Trip updated', 'trip.toast.placeAdded': 'Place added', diff --git a/shared/src/i18n/es/trip.ts b/shared/src/i18n/es/trip.ts index 821e9a288..7506f2c44 100644 --- a/shared/src/i18n/es/trip.ts +++ b/shared/src/i18n/es/trip.ts @@ -18,6 +18,7 @@ const trip: TranslationStrings = { 'trip.loadingSteps.arrive': 'Ya casi llegamos...', 'trip.mobilePlan': 'Plan', 'trip.mobilePlaces': 'Lugares', + 'trip.panelWidth': 'Ancho del panel', 'trip.toast.placeUpdated': 'Lugar actualizado', 'trip.toast.tripUpdated': 'Viaje actualizado', 'trip.toast.placeAdded': 'Lugar añadido', diff --git a/shared/src/i18n/et/trip.ts b/shared/src/i18n/et/trip.ts index 7f57f031a..6518af4a5 100644 --- a/shared/src/i18n/et/trip.ts +++ b/shared/src/i18n/et/trip.ts @@ -18,6 +18,7 @@ const trip: TranslationStrings = { 'trip.loadingSteps.arrive': 'Peaaegu kohal...', 'trip.mobilePlan': 'Plaan', 'trip.mobilePlaces': 'Kohad', + 'trip.panelWidth': 'Paneeli laius', 'trip.toast.placeUpdated': 'Koht uuendatud', 'trip.toast.tripUpdated': 'Reis uuendatud', 'trip.toast.placeAdded': 'Koht lisatud', diff --git a/shared/src/i18n/fr/trip.ts b/shared/src/i18n/fr/trip.ts index bf441115b..d2b6cc160 100644 --- a/shared/src/i18n/fr/trip.ts +++ b/shared/src/i18n/fr/trip.ts @@ -18,6 +18,7 @@ const trip: TranslationStrings = { 'trip.loadingSteps.arrive': 'On y est presque...', 'trip.mobilePlan': 'Plan', 'trip.mobilePlaces': 'Lieux', + 'trip.panelWidth': 'Largeur du panneau', 'trip.toast.placeUpdated': 'Lieu mis à jour', 'trip.toast.tripUpdated': 'Voyage mis à jour', 'trip.toast.placeAdded': 'Lieu ajouté', diff --git a/shared/src/i18n/gr/trip.ts b/shared/src/i18n/gr/trip.ts index 121e8a27f..b3782aa4b 100644 --- a/shared/src/i18n/gr/trip.ts +++ b/shared/src/i18n/gr/trip.ts @@ -18,6 +18,7 @@ const trip: TranslationStrings = { 'trip.loadingSteps.arrive': 'Σχεδόν φτάσαμε...', 'trip.mobilePlan': 'Πλάνο', 'trip.mobilePlaces': 'Μέρη', + 'trip.panelWidth': 'Πλάτος πλαισίου', 'trip.toast.placeUpdated': 'Το μέρος ενημερώθηκε', 'trip.toast.tripUpdated': 'Το ταξίδι ενημερώθηκε', 'trip.toast.placeAdded': 'Το μέρος προστέθηκε', diff --git a/shared/src/i18n/hu/trip.ts b/shared/src/i18n/hu/trip.ts index 73feab850..32adbdec4 100644 --- a/shared/src/i18n/hu/trip.ts +++ b/shared/src/i18n/hu/trip.ts @@ -14,6 +14,7 @@ const trip: TranslationStrings = { 'trip.loading': 'Utazás betöltése...', 'trip.mobilePlan': 'Tervezés', 'trip.mobilePlaces': 'Helyek', + 'trip.panelWidth': 'Panel szélessége', 'trip.toast.placeUpdated': 'Hely frissítve', 'trip.toast.tripUpdated': 'Utazás frissítve', 'trip.toast.placeAdded': 'Hely hozzáadva', diff --git a/shared/src/i18n/id/trip.ts b/shared/src/i18n/id/trip.ts index 7e8bdbed6..f29ee43f4 100644 --- a/shared/src/i18n/id/trip.ts +++ b/shared/src/i18n/id/trip.ts @@ -18,6 +18,7 @@ const trip: TranslationStrings = { 'trip.loadingSteps.arrive': 'Hampir sampai...', 'trip.mobilePlan': 'Rencana', 'trip.mobilePlaces': 'Tempat', + 'trip.panelWidth': 'Lebar panel', 'trip.toast.placeUpdated': 'Tempat diperbarui', 'trip.toast.tripUpdated': 'Perjalanan diperbarui', 'trip.toast.placeAdded': 'Tempat ditambahkan', diff --git a/shared/src/i18n/it/trip.ts b/shared/src/i18n/it/trip.ts index 09dc9fa41..ddd82a89e 100644 --- a/shared/src/i18n/it/trip.ts +++ b/shared/src/i18n/it/trip.ts @@ -14,6 +14,7 @@ const trip: TranslationStrings = { 'trip.loading': 'Caricamento viaggio...', 'trip.mobilePlan': 'Programma', 'trip.mobilePlaces': 'Luoghi', + 'trip.panelWidth': 'Larghezza del pannello', 'trip.toast.placeUpdated': 'Luogo aggiornato', 'trip.toast.tripUpdated': 'Viaggio aggiornato', 'trip.toast.placeAdded': 'Luogo aggiunto', diff --git a/shared/src/i18n/ja/trip.ts b/shared/src/i18n/ja/trip.ts index 3065a98ff..2230b8976 100644 --- a/shared/src/i18n/ja/trip.ts +++ b/shared/src/i18n/ja/trip.ts @@ -18,6 +18,7 @@ const trip: TranslationStrings = { 'trip.loadingSteps.arrive': 'もうすぐ到着...', 'trip.mobilePlan': '計画', 'trip.mobilePlaces': '場所', + 'trip.panelWidth': 'パネルの幅', 'trip.toast.placeUpdated': '場所を更新しました', 'trip.toast.tripUpdated': '旅行を更新しました', 'trip.toast.placeAdded': '場所を追加しました', diff --git a/shared/src/i18n/ko/trip.ts b/shared/src/i18n/ko/trip.ts index 6b85c97ce..23fd90360 100644 --- a/shared/src/i18n/ko/trip.ts +++ b/shared/src/i18n/ko/trip.ts @@ -18,6 +18,7 @@ const trip: TranslationStrings = { 'trip.loadingSteps.arrive': '거의 다 왔어요...', 'trip.mobilePlan': '계획', 'trip.mobilePlaces': '장소', + 'trip.panelWidth': '패널 너비', 'trip.toast.placeUpdated': '장소가 업데이트되었습니다', 'trip.toast.tripUpdated': '여행이 업데이트됨', 'trip.toast.placeAdded': '장소가 추가되었습니다', diff --git a/shared/src/i18n/nl/trip.ts b/shared/src/i18n/nl/trip.ts index 942983a5e..0dd8a6798 100644 --- a/shared/src/i18n/nl/trip.ts +++ b/shared/src/i18n/nl/trip.ts @@ -18,6 +18,7 @@ const trip: TranslationStrings = { 'trip.loadingSteps.arrive': 'Bijna aangekomen...', 'trip.mobilePlan': 'Plan', 'trip.mobilePlaces': 'Plaatsen', + 'trip.panelWidth': 'Paneelbreedte', 'trip.toast.placeUpdated': 'Plaats bijgewerkt', 'trip.toast.tripUpdated': 'Reis bijgewerkt', 'trip.toast.placeAdded': 'Plaats toegevoegd', diff --git a/shared/src/i18n/pl/trip.ts b/shared/src/i18n/pl/trip.ts index 3286692a3..99a97da52 100644 --- a/shared/src/i18n/pl/trip.ts +++ b/shared/src/i18n/pl/trip.ts @@ -14,6 +14,7 @@ const trip: TranslationStrings = { 'trip.loading': 'Ładowanie podróży...', 'trip.mobilePlan': 'Plan', 'trip.mobilePlaces': 'Miejsca', + 'trip.panelWidth': 'Szerokość panelu', 'trip.toast.placeUpdated': 'Miejsce zostało zaktualizowane', 'trip.toast.tripUpdated': 'Podróż zaktualizowana', 'trip.toast.placeAdded': 'Miejsce zostało dodane', diff --git a/shared/src/i18n/ru/trip.ts b/shared/src/i18n/ru/trip.ts index bf9b294aa..db07a124a 100644 --- a/shared/src/i18n/ru/trip.ts +++ b/shared/src/i18n/ru/trip.ts @@ -18,6 +18,7 @@ const trip: TranslationStrings = { 'trip.loadingSteps.arrive': 'Почти на месте...', 'trip.mobilePlan': 'План', 'trip.mobilePlaces': 'Места', + 'trip.panelWidth': 'Ширина панели', 'trip.toast.placeUpdated': 'Место обновлено', 'trip.toast.tripUpdated': 'Поездка обновлена', 'trip.toast.placeAdded': 'Место добавлено', diff --git a/shared/src/i18n/sk/trip.ts b/shared/src/i18n/sk/trip.ts index 240288c30..be366b781 100644 --- a/shared/src/i18n/sk/trip.ts +++ b/shared/src/i18n/sk/trip.ts @@ -18,6 +18,7 @@ const trip: TranslationStrings = { 'trip.loadingSteps.arrive': 'Už sme skoro tam...', 'trip.mobilePlan': 'Plán', 'trip.mobilePlaces': 'Miesta', + 'trip.panelWidth': 'Šírka panela', 'trip.toast.placeUpdated': 'Miesto bolo aktualizované', 'trip.toast.tripUpdated': 'Cesta aktualizovaná', 'trip.toast.placeAdded': 'Miesto bolo pridané', diff --git a/shared/src/i18n/sv/trip.ts b/shared/src/i18n/sv/trip.ts index f76503f69..52bcf47c6 100644 --- a/shared/src/i18n/sv/trip.ts +++ b/shared/src/i18n/sv/trip.ts @@ -18,6 +18,7 @@ const trip: TranslationStrings = { 'trip.loadingSteps.arrive': 'Snart framme...', 'trip.mobilePlan': 'Plan', 'trip.mobilePlaces': 'Platser', + 'trip.panelWidth': 'Panelens bredd', 'trip.toast.placeUpdated': 'Plats uppdaterad', 'trip.toast.tripUpdated': 'Resan uppdaterad', 'trip.toast.placeAdded': 'Plats tillagd', diff --git a/shared/src/i18n/th/trip.ts b/shared/src/i18n/th/trip.ts index e4734057b..f00d6e16c 100644 --- a/shared/src/i18n/th/trip.ts +++ b/shared/src/i18n/th/trip.ts @@ -18,6 +18,7 @@ const trip: TranslationStrings = { 'trip.loadingSteps.arrive': "เกือบจะถึงแล้ว...", 'trip.mobilePlan': "แผน", 'trip.mobilePlaces': "สถานที่", + 'trip.panelWidth': 'ความกว้างของแผง', 'trip.toast.placeUpdated': "อัปเดตสถานที่แล้ว", 'trip.toast.tripUpdated': "อัปเดตการเดินทางแล้ว", 'trip.toast.placeAdded': "เพิ่มสถานที่แล้ว", diff --git a/shared/src/i18n/tr/trip.ts b/shared/src/i18n/tr/trip.ts index d2ef5b608..7859505a3 100644 --- a/shared/src/i18n/tr/trip.ts +++ b/shared/src/i18n/tr/trip.ts @@ -18,6 +18,7 @@ const trip: TranslationStrings = { 'trip.loadingSteps.arrive': 'Az kaldı...', 'trip.mobilePlan': 'Plan', 'trip.mobilePlaces': 'Yerler', + 'trip.panelWidth': 'Panel genişliği', 'trip.toast.placeUpdated': 'Yer güncellendi', 'trip.toast.tripUpdated': 'Gezi güncellendi', 'trip.toast.placeAdded': 'Yer eklendi', diff --git a/shared/src/i18n/uk/trip.ts b/shared/src/i18n/uk/trip.ts index bc03a8fe8..648f2f666 100644 --- a/shared/src/i18n/uk/trip.ts +++ b/shared/src/i18n/uk/trip.ts @@ -18,6 +18,7 @@ const trip: TranslationStrings = { 'trip.loadingSteps.arrive': 'Майже на місці...', 'trip.mobilePlan': 'План', 'trip.mobilePlaces': 'Місця', + 'trip.panelWidth': 'Ширина панелі', 'trip.toast.placeUpdated': 'Місце оновлено', 'trip.toast.tripUpdated': 'Подорож оновлено', 'trip.toast.placeAdded': 'Місце додано', diff --git a/shared/src/i18n/vi/trip.ts b/shared/src/i18n/vi/trip.ts index d78cbb716..f5b665b7c 100644 --- a/shared/src/i18n/vi/trip.ts +++ b/shared/src/i18n/vi/trip.ts @@ -18,6 +18,7 @@ const trip: TranslationStrings = { 'trip.loadingSteps.arrive': 'Sắp đến nơi rồi...', 'trip.mobilePlan': 'Kế hoạch', 'trip.mobilePlaces': 'Địa điểm', + 'trip.panelWidth': 'Độ rộng bảng', 'trip.toast.placeUpdated': 'Đã cập nhật địa điểm', 'trip.toast.tripUpdated': 'Đã cập nhật chuyến đi', 'trip.toast.placeAdded': 'Đã thêm địa điểm', diff --git a/shared/src/i18n/zh-TW/trip.ts b/shared/src/i18n/zh-TW/trip.ts index c9053fd69..5da1faef2 100644 --- a/shared/src/i18n/zh-TW/trip.ts +++ b/shared/src/i18n/zh-TW/trip.ts @@ -18,6 +18,7 @@ const trip: TranslationStrings = { 'trip.loadingSteps.arrive': '就快抵達了...', 'trip.mobilePlan': '計劃', 'trip.mobilePlaces': '地點', + 'trip.panelWidth': '面板寬度', 'trip.toast.placeUpdated': '地點已更新', 'trip.toast.tripUpdated': '行程已更新', 'trip.toast.placeAdded': '地點已新增', diff --git a/shared/src/i18n/zh/trip.ts b/shared/src/i18n/zh/trip.ts index 072a44c55..696cf961a 100644 --- a/shared/src/i18n/zh/trip.ts +++ b/shared/src/i18n/zh/trip.ts @@ -18,6 +18,7 @@ const trip: TranslationStrings = { 'trip.loadingSteps.arrive': '就快到啦...', 'trip.mobilePlan': '计划', 'trip.mobilePlaces': '地点', + 'trip.panelWidth': '面板宽度', 'trip.toast.placeUpdated': '地点已更新', 'trip.toast.tripUpdated': '行程已更新', 'trip.toast.placeAdded': '地点已添加',