From 7710ff8fa19e5ef8d3fc64f507c68574e89c8b91 Mon Sep 17 00:00:00 2001 From: Alexander Platov <alexander.platov@hardcoreeng.com> Date: Fri, 1 Nov 2024 13:53:56 +0300 Subject: [PATCH] Mobile layout fixes (#7077) Signed-off-by: Alexander Platov <alexander.platov@hardcoreeng.com> --- packages/theme/styles/_layouts.scss | 1 + packages/ui/src/components/Separator.svelte | 19 ++++++++--- packages/ui/src/resize.ts | 2 +- .../src/components/ControlBar.svelte | 34 ++++++++++++++++--- .../love-resources/src/components/Room.svelte | 21 ++++++++++-- .../src/components/Workbench.svelte | 12 +++++++ .../src/components/WorkbenchTabs.svelte | 26 +++++++------- 7 files changed, 90 insertions(+), 25 deletions(-) diff --git a/packages/theme/styles/_layouts.scss b/packages/theme/styles/_layouts.scss index 3247cfbf48..54f7d76568 100644 --- a/packages/theme/styles/_layouts.scss +++ b/packages/theme/styles/_layouts.scss @@ -1053,6 +1053,7 @@ a.no-line { .bottom-divider { border-bottom: 1px solid var(--theme-divider-color); } .left-divider { border-left: 1px solid var(--theme-divider-color); } .right-divider { border-right: 1px solid var(--theme-divider-color); } +.right-navpanel-border { border-right: 1px solid var(--theme-navpanel-border); } .bottom-highlight-select { border-bottom: 1px solid var(--highlight-select); } diff --git a/packages/ui/src/components/Separator.svelte b/packages/ui/src/components/Separator.svelte index 613177ce66..7ab8e37f72 100644 --- a/packages/ui/src/components/Separator.svelte +++ b/packages/ui/src/components/Separator.svelte @@ -38,6 +38,8 @@ let sState: SeparatorState $: sState = typeof float === 'string' ? SeparatorState.FLOAT : float ? SeparatorState.HIDDEN : SeparatorState.NORMAL + const checkFullWidth = (): boolean => + sState === SeparatorState.FLOAT && $deviceInfo.isMobile && $deviceInfo.isPortrait const direction: 'horizontal' | 'vertical' = 'horizontal' let separators: SeparatedItem[] | null = null @@ -67,6 +69,10 @@ let disabled: boolean = false let side: 'start' | 'end' | undefined = undefined + $: fs = $deviceInfo.fontSize + const remToPx = (rem: number): number => rem * fs + const pxToRem = (px: number): number => px / fs + const fetchSeparators = (): void => { const res = getSeparators(name, float) if (res !== null && !Array.isArray(res)) panel = res @@ -90,10 +96,6 @@ checkSizes() } - $: fs = $deviceInfo.fontSize - const remToPx = (rem: number): number => rem * fs - const pxToRem = (px: number): number => px / fs - const convertSize = (prop: TSeparatedItem): string => (typeof prop === 'number' ? `${prop}px` : '') const setSize = (element: HTMLElement, size: TSeparatedItem, next: boolean = false): void => { @@ -229,6 +231,12 @@ const checkSizes = (): void => { if (sState === SeparatorState.FLOAT) { + if (checkFullWidth() && panel != null) { + const s = pxToRem(window.innerWidth) + panel.size = s + panel.maxSize = s + panel.minSize = s + } if (parentElement != null && panel != null) initSize(parentElement, panel) } else if (sState === SeparatorState.NORMAL) { if (prevElement != null && prevElSize != null) initSize(prevElement, prevElSize) @@ -442,12 +450,13 @@ } } else if (sState === SeparatorState.FLOAT && parentElement != null) { parentElement.style.pointerEvents = 'all' - saveSeparator(name, float, panel) + if (!checkFullWidth()) saveSeparator(name, float, panel) } document.body.style.cursor = '' } function pointerDown (event: PointerEvent): void { + if (checkFullWidth()) return prepareSeparation(event) document.addEventListener('pointermove', pointerMove) document.addEventListener('pointerup', pointerUp) diff --git a/packages/ui/src/resize.ts b/packages/ui/src/resize.ts index 7ebae9e983..29fd80c43d 100644 --- a/packages/ui/src/resize.ts +++ b/packages/ui/src/resize.ts @@ -148,7 +148,7 @@ export function saveSeparator ( } export const panelSeparators: DefSeparators = [ - { minSize: 30, size: 'auto', maxSize: 'auto' }, + { minSize: 20, size: 'auto', maxSize: 'auto' }, { minSize: 17, size: 25, maxSize: 35, float: 'aside' } ] diff --git a/plugins/love-resources/src/components/ControlBar.svelte b/plugins/love-resources/src/components/ControlBar.svelte index c834f3b508..ef0541396c 100644 --- a/plugins/love-resources/src/components/ControlBar.svelte +++ b/plugins/love-resources/src/components/ControlBar.svelte @@ -28,7 +28,8 @@ getCurrentLocation, showPopup, type AnySvelteComponent, - type CompAndProps + type CompAndProps, + resizeObserver } from '@hcengineering/ui' import view from '@hcengineering/view' import plugin from '../plugin' @@ -51,6 +52,7 @@ import CamSettingPopup from './CamSettingPopup.svelte' import MicSettingPopup from './MicSettingPopup.svelte' import RoomAccessPopup from './RoomAccessPopup.svelte' + import { afterUpdate } from 'svelte' export let room: Room export let fullScreen: boolean = false @@ -59,6 +61,11 @@ const allowShare: boolean = true let allowLeave: boolean = false let popup: CompAndProps | undefined = undefined + let grow: HTMLElement + let leftPanel: HTMLElement + let leftPanelSize: number = 0 + let noLabel: boolean = false + let combinePanel: boolean = false $: allowCam = $currentRoom?.type === RoomType.Video $: allowLeave = $myInfo?.room !== ($myOffice?._id ?? plugin.ids.Reception) @@ -149,9 +156,22 @@ const camKeys = client.getModel().findAllSync(view.class.Action, { _id: plugin.action.ToggleVideo })?.[0]?.keyBinding const micKeys = client.getModel().findAllSync(view.class.Action, { _id: plugin.action.ToggleMic })?.[0]?.keyBinding + + const checkBar = (): void => { + if (grow === undefined || leftPanel === undefined) return + if (!noLabel && leftPanel.clientWidth > leftPanelSize) leftPanelSize = leftPanel.clientWidth + if (grow.clientWidth - 16 < leftPanel.clientWidth && !noLabel && !combinePanel) noLabel = true + else if (grow.clientWidth - 16 < leftPanel.clientWidth && noLabel && !combinePanel) combinePanel = true + else if (grow.clientWidth * 2 - 32 > leftPanel.clientWidth && noLabel && combinePanel) combinePanel = false + else if (grow.clientWidth - 32 >= leftPanelSize && noLabel && !combinePanel) noLabel = false + } + afterUpdate(() => { + checkBar() + }) </script> -<div class="bar w-full flex-center flex-gap-2 flex-no-shrink"> +<div class="bar w-full flex-center flex-gap-2 flex-no-shrink" class:combinePanel use:resizeObserver={checkBar}> + <div bind:this={grow} class="flex-grow" /> {#if room._id !== plugin.ids.Reception} <ModernButton icon={roomAccessIcon[room.access]} @@ -205,7 +225,7 @@ /> {/if} {/if} - <div class="bar__left-panel flex-gap-2 flex-center"> + <div bind:this={leftPanel} class="bar__left-panel flex-gap-2 flex-center"> {#if $isConnected} <ModernButton icon={$isFullScreen ? love.icon.ExitFullScreen : love.icon.FullScreen} @@ -232,7 +252,7 @@ {#if allowLeave} <ModernButton icon={plugin.icon.LeaveRoom} - label={plugin.string.LeaveRoom} + label={noLabel ? undefined : plugin.string.LeaveRoom} tooltip={{ label: plugin.string.LeaveRoom, direction: 'top' }} kind={'negative'} size={'large'} @@ -240,6 +260,7 @@ /> {/if} </div> + <div class="flex-grow" /> {#if popup && fullScreen} <PopupInstance is={popup.is} @@ -259,6 +280,7 @@ <style lang="scss"> .bar { + overflow-x: auto; position: relative; padding: 1rem; border-top: 1px solid var(--theme-divider-color); @@ -270,5 +292,9 @@ right: 1rem; height: 100%; } + + &.combinePanel .bar__left-panel { + position: static; + } } </style> diff --git a/plugins/love-resources/src/components/Room.svelte b/plugins/love-resources/src/components/Room.svelte index e1d2bd92d4..93f8f6d093 100644 --- a/plugins/love-resources/src/components/Room.svelte +++ b/plugins/love-resources/src/components/Room.svelte @@ -17,7 +17,7 @@ import { personByIdStore } from '@hcengineering/contact-resources' import { Room as TypeRoom } from '@hcengineering/love' import { getMetadata } from '@hcengineering/platform' - import { Label, Loading, resizeObserver } from '@hcengineering/ui' + import { Label, Loading, resizeObserver, deviceOptionsStore as deviceInfo } from '@hcengineering/ui' import { LocalParticipant, LocalTrackPublication, @@ -333,7 +333,7 @@ $: if (((document.fullscreenElement && !$isFullScreen) || $isFullScreen) && roomEl) toggleFullscreen() </script> -<div bind:this={roomEl} class="flex-col-center w-full h-full" class:theme-dark={$isFullScreen}> +<div bind:this={roomEl} class="flex-col-center w-full h-full right-navpanel-border" class:theme-dark={$isFullScreen}> {#if $isConnected && !$isCurrentInstanceConnected} <div class="flex justify-center error h-full w-full clear-mins"> <Label label={love.string.AnotherWindowError} /> @@ -345,7 +345,13 @@ {:else if loading} <Loading /> {/if} - <div class="room-container" class:sharing={$screenSharing} class:many={columns > 3} class:hidden={loading}> + <div + class="room-container" + class:sharing={$screenSharing} + class:many={columns > 3} + class:hidden={loading} + class:mobile={$deviceInfo.isMobile} + > <div class="screenContainer"> <video class="screen" bind:this={screen}></video> </div> @@ -452,6 +458,15 @@ gap: 0.5rem; } } + + &.mobile { + padding: var(--spacing-0_5); + + &:not(.sharing) .videoGrid, + &.sharing { + gap: var(--spacing-0_5); + } + } } .hidden { display: none; diff --git a/plugins/workbench-resources/src/components/Workbench.svelte b/plugins/workbench-resources/src/components/Workbench.svelte index 5a05d4788e..24f5ad5b49 100644 --- a/plugins/workbench-resources/src/components/Workbench.svelte +++ b/plugins/workbench-resources/src/components/Workbench.svelte @@ -647,6 +647,18 @@ const checkOnHide = (): void => { if ($deviceInfo.navigator.visible && $deviceInfo.docWidth <= 1024) $deviceInfo.navigator.visible = false } + let oldNavVisible: boolean = $deviceInfo.navigator.visible + let oldASideVisible: boolean = $deviceInfo.aside.visible + $: if (oldNavVisible !== $deviceInfo.navigator.visible || oldASideVisible !== $deviceInfo.aside.visible) { + if ($deviceInfo.isMobile && $deviceInfo.isPortrait && $deviceInfo.navigator.float) { + if ($deviceInfo.navigator.visible && $deviceInfo.aside.visible) { + if (oldNavVisible) $deviceInfo.navigator.visible = false + else $deviceInfo.aside.visible = false + } + } + oldNavVisible = $deviceInfo.navigator.visible + oldASideVisible = $deviceInfo.aside.visible + } $: $deviceInfo.navigator.direction = $deviceInfo.isMobile && $deviceInfo.isPortrait ? 'horizontal' : 'vertical' let appsMini: boolean $: appsMini = diff --git a/plugins/workbench-resources/src/components/WorkbenchTabs.svelte b/plugins/workbench-resources/src/components/WorkbenchTabs.svelte index e7c950a24e..6a32f54119 100644 --- a/plugins/workbench-resources/src/components/WorkbenchTabs.svelte +++ b/plugins/workbench-resources/src/components/WorkbenchTabs.svelte @@ -57,23 +57,25 @@ </div> </div> {:else if !mini} - <ScrollerBar bind:scroller padding={'.25rem 0'}> + <div class="flex-row-center gap-1 py-1 overflow-x-auto"> {#each $tabsStore as tab (tab._id)} <WorkbenchTabPresenter {tab} /> {/each} - </ScrollerBar> + </div> {:else if selectedTab !== undefined} <WorkbenchTabPresenter tab={selectedTab} /> - <ButtonIcon - bind:element - icon={IconMoreH} - iconProps={{ fill: 'var(--theme-dark-color)' }} - size={'extra-small'} - kind={'tertiary'} - hasMenu - {pressed} - on:click={showTabs} - /> + {#if $tabsStore.length > 1} + <ButtonIcon + bind:element + icon={IconMoreH} + iconProps={{ fill: 'var(--theme-dark-color)' }} + size={'extra-small'} + kind={'tertiary'} + hasMenu + {pressed} + on:click={showTabs} + /> + {/if} {/if} {#if !popup} <ButtonIcon