UBER-984: UI fixes, Panel auto resize (#3818)

Signed-off-by: Alexander Platov <sas_lord@mail.ru>
This commit is contained in:
Alexander Platov 2023-10-10 10:53:26 +03:00 committed by GitHub
parent 1ca3c7ba39
commit b2576d718f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 115 additions and 46 deletions

View File

@ -6,10 +6,11 @@
<title>Platform</title>
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="manifest" href="/site.webmanifest">
<link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
<link rel="icon" type="image/svg+xml" sizes="any" href="favicon.svg">
<link rel="icon" type="image/png" sizes="16x16" href="favicon_16.png">
<link rel="icon" type="image/png" sizes="32x32" href="favicon_32.png">
<link rel="icon" type="image/png" sizes="192x192" href="favicon_192.png">
</head>
<body style="margin: 0; overflow: hidden;">

View File

@ -58,6 +58,7 @@
export let readonly = false
export let disallowDeselect: Ref<Doc>[] | undefined = undefined
export let created: Doc[] = []
export let embedded: boolean = false
let search: string = ''
@ -158,6 +159,7 @@
class:full-width={width === 'full'}
class:plainContainer={!shadows}
class:width-40={width === 'large'}
class:embedded
on:keydown={onKeydown}
use:resizeObserver={() => {
dispatch('changeContent')
@ -230,7 +232,7 @@
</ListView>
</div>
</div>
<div class="menu-space" />
{#if !embedded}<div class="menu-space" />{/if}
</div>
<style lang="scss">

View File

@ -58,7 +58,7 @@
<!-- svelte-ignore a11y-click-events-have-key-events -->
<span
class:cursor-pointer={!disabled}
class:noUnderline
class:noUnderline={noUnderline || disabled}
class:noOverflow
class:inline
class:colorInherit
@ -71,7 +71,7 @@
{:else}
<a
{href}
class:noUnderline
class:noUnderline={noUnderline || disabled}
class:noOverflow
class:inline
class:colorInherit

View File

@ -46,6 +46,7 @@
export let create: ObjectCreate | undefined = undefined
export let readonly = false
export let disallowDeselect: Ref<Doc>[] | undefined = undefined
export let embedded: boolean = false
export let filter: (it: Doc) => boolean = () => {
return true
@ -108,6 +109,7 @@
{create}
{readonly}
{disallowDeselect}
{embedded}
on:update
on:close
on:changeContent

View File

@ -240,7 +240,6 @@
&__aside {
width: 25%;
min-width: var(--panel-aside-width);
border-left: 1px solid var(--theme-divider-color);
&.float {
position: absolute;
@ -252,6 +251,7 @@
max-width: var(--panel-aside-width);
height: 100%;
background-color: var(--theme-panel-color);
border-left: 1px solid var(--theme-divider-color);
border-bottom-right-radius: .45rem;
box-shadow: 0 0 0 0 rgba(0, 0, 0, 0);
transition: box-shadow 150ms ease 0s, transform 150ms cubic-bezier(0.175, 0.885, 0.32, 1.275);

View File

@ -23,12 +23,15 @@
max-width: 17rem;
max-height: 22rem;
&:not(.embedded) {
background: var(--theme-popup-color);
border: 1px solid var(--theme-popup-divider);
border-radius: .5rem;
box-shadow: var(--theme-popup-shadow);
}
&.noShadow {
&.noShadow,
&.embedded {
background: none;
border: none;
box-shadow: none;

View File

@ -19,7 +19,7 @@
import { closePanel, PanelProps, panelstore } from '../panelup'
import { fitPopupElement, popupstore } from '../popups'
import { deviceOptionsStore as deviceInfo } from '..'
import { deviceOptionsStore as deviceInfo, resizeObserver } from '..'
import type { AnySvelteComponent, PopupOptions, DeviceOptions } from '../types'
import Spinner from './Spinner.svelte'
@ -45,6 +45,7 @@
}
let component: AnySvelteComponent | undefined
let keepSize: boolean = false
let props: PanelProps | undefined
function _close () {
@ -107,8 +108,16 @@
}
}
const checkResize = (el: Element) => {
if (props) fitPopup(props, contentPanel)
}
afterUpdate(() => {
if (props) fitPopup(props, contentPanel)
if (!keepSize && props?.element === 'content' && contentPanel !== undefined) {
keepSize = true
resizeObserver(contentPanel, checkResize)
}
})
export function fitPopupInstance (): void {
if (props) fitPopup(props, contentPanel)

View File

@ -52,6 +52,7 @@
export let size: 'small' | 'medium' | 'large' = 'small'
export let onSelect: ((value: ValueType['id']) => void) | undefined = undefined
export let showShadow: boolean = true
export let embedded: boolean = false
let search: string = ''
@ -101,6 +102,7 @@
class:noShadow={showShadow === false}
class:full-width={width === 'full'}
class:max-width-40={width === 'large'}
class:embedded
use:resizeObserver={() => {
dispatch('changeContent')
}}
@ -179,5 +181,5 @@
</ListView>
</div>
</div>
<div class="menu-space" />
{#if !embedded}<div class="menu-space" />{/if}
</div>

View File

@ -26,7 +26,7 @@
export let prevElementSize: SeparatedItem | undefined = undefined
export let nextElementSize: SeparatedItem | undefined = undefined
export let separatorSize: number = 1
export let color: string = 'var(--theme-navpanel-border)'
export let color: string = 'var(--theme-divider-color)'
export let name: string
export let index: number // index = -1 ; for custom sizes without saving to a localStorage
@ -412,7 +412,7 @@
&::before {
position: absolute;
content: '';
z-index: 10;
z-index: 402;
}
&::after {
background-color: var(--theme-primary-default);

View File

@ -132,7 +132,7 @@
departmentById={departments}
on:selected={(e) => departmentSelected(e.detail)}
/>
<Separator name={'workbench'} index={0} />
<Separator name={'workbench'} index={0} color={'var(--theme-navpanel-border)'} />
{/if}
<div class="antiPanel-component filled">

View File

@ -139,7 +139,7 @@
<div class="flex-row-top h-full">
{#if visibileNav}
<div class="antiPanel-component header border-right aside min-w-100 flex-no-shrink">
<div class="antiPanel-component header aside min-w-100 flex-no-shrink">
<Tabs
bind:selected={selectedTab}
model={tabs}

View File

@ -46,9 +46,9 @@
{:else}
<div class="flex-presenter" use:tooltip={{ label: getEmbeddedLabel(value.name) }}>
<div class="icon"><Icon icon={recruit.icon.Vacancy} size={'small'} /></div>
<span class="label nowrap" class:no-underline={noUnderline || disabled} class:fs-bold={accent}
>{value.name}</span
>
<span class="label nowrap" class:no-underline={noUnderline || disabled} class:fs-bold={accent}>
{value.name}
</span>
</div>
{/if}
</DocNavLink>

View File

@ -10,9 +10,11 @@
import { IntlString } from '@hcengineering/platform'
export let value: Task | Task[]
export let width: 'medium' | 'large' | 'full' = 'medium'
export let placeholder: IntlString
export let ofAttribute: Ref<Attribute<Status>>
export let _class: Ref<Class<Status>>
export let embedded: boolean = false
const queryOptions: FindOptions<Status> = {
lookup: {
@ -91,6 +93,8 @@
changeStatus(evt.detail === null ? null : evt.detail?._id)
}}
{placeholder}
{width}
{embedded}
on:changeContent
>
<svelte:fragment slot="item" let:item>

View File

@ -31,6 +31,7 @@
export let justify: 'left' | 'center' = 'center'
export let shouldShowName: boolean = true
export let shrink: number = 0
export let disabled: boolean = false
$: state = $statusStore.get(value)
let opened: boolean = false
@ -50,13 +51,13 @@
</script>
{#if kind === 'list' || kind === 'list-header'}
<StatePresenter value={state} {shouldShowName} shouldShowTooltip on:click={handleClick} />
<StatePresenter value={state} {shouldShowName} {disabled} shouldShowTooltip on:click={handleClick} />
{:else}
<Button {kind} {size} {width} {justify} {shrink} on:click={handleClick}>
<svelte:fragment slot="content">
{#if state}
<div class="pointer-events-none clear-mins">
<StatePresenter value={state} {shouldShowName} />
<StatePresenter value={state} {shouldShowName} {disabled} />
</div>
{/if}
</svelte:fragment>

View File

@ -32,6 +32,7 @@
export let shouldShowName: boolean = true
export let shouldShowTooltip: boolean = false
export let noUnderline: boolean = false
export let shrink: number = 0
const dispatch = createEventDispatcher()
@ -47,7 +48,12 @@
{#if value}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div class="flex-presenter" class:inline-presenter={inline} on:click>
<div
class="flex-presenter"
class:inline-presenter={inline}
class:flex-no-shrink={!shouldShowName || shrink === 0}
on:click
>
{#if shouldShowAvatar}
<div
class="state-container"
@ -58,9 +64,9 @@
/>
{/if}
{#if shouldShowName}
<span class="overflow-label label" class:nowrap={oneLine} class:no-underline={noUnderline || disabled}
>{value.name}</span
>
<span class="overflow-label label" class:nowrap={oneLine} class:no-underline={noUnderline || disabled}>
{value.name}
</span>
{/if}
</div>
{/if}

View File

@ -28,14 +28,15 @@
export let size: ButtonSize = 'medium'
export let shouldShowName: boolean = true
export let shrink: number = 0
export let disabled: boolean = false
$: state = $statusStore.get(typeof value === 'string' ? value : (value?.values?.[0]?._id as Ref<Status>))
</script>
{#if value}
{#if onChange !== undefined && state !== undefined}
<StateEditor value={state._id} {space} {onChange} {kind} {size} {shouldShowName} {shrink} />
<StateEditor value={state._id} {space} {onChange} {kind} {size} {shouldShowName} {shrink} {disabled} />
{:else}
<StatePresenter value={state} {shouldShowName} on:accent-color />
<StatePresenter value={state} {shouldShowName} {disabled} {shrink} on:accent-color />
{/if}
{/if}

View File

@ -24,7 +24,7 @@
export let value: WithLookup<Component> | undefined
export let shouldShowAvatar = true
export let onClick: (() => void) | undefined = undefined
export let disabled = false
export let disabled: boolean = false
export let inline: boolean = false
export let accent: boolean = false
export let noUnderline = false

View File

@ -21,10 +21,12 @@
export let value: Ref<Component> | AggregateValue | undefined
export let kind: 'list' | undefined = undefined
export let disabled: boolean = false
export let accent: boolean = false
$: componentValue = $componentStore.get(
typeof value === 'string' ? value : (value?.values?.[0]?._id as Ref<Component>)
)
</script>
<ComponentPresenter value={componentValue} {kind} on:accent-color />
<ComponentPresenter value={componentValue} {kind} {disabled} {accent} on:accent-color />

View File

@ -37,7 +37,7 @@
})
</script>
<div class="flex-presenter cursor-default">
<div class="flex-presenter">
{#if !inline && icon}
<Icon {icon} {size} fill={'var(--theme-caption-color)'} />
{/if}

View File

@ -27,7 +27,7 @@
</script>
{#if value}
<div class="flex-presenter cursor-default" style:color={'inherit'}>
<div class="flex-presenter" style:color={'inherit'}>
{#if !inline}
<IssueStatusIcon {value} {size} {space} on:accent-color />
{/if}

View File

@ -31,6 +31,7 @@
"SelectItem": "Select focused item",
"SelectItemAll": "Select all items",
"SelectItemNone": "Deselect all items",
"NumberItems": "{count, plural, =0 {no items} =1 {1 item} other {# items}}",
"Assigned": "Assigned",
"Created": "Created",

View File

@ -35,6 +35,7 @@
"SelectItem": "Выбрать",
"SelectItemAll": "Выбрать все",
"SelectItemNone": "Снять все выделения",
"NumberItems": "{count, plural, =0 {нет объектов} one {# объект} few {# объекта} other {# объектов}}",
"Assigned": "Назначенные",
"Created": "Созданные",
"Subscribed": "Отслеживаемые",

View File

@ -194,10 +194,10 @@
use:resizeObserver={() => dispatch('changeContent')}
>
{#if $selectionStore.length > 0 || $focusStore.focus !== undefined || (activeAction && activeAction?.actionPopup !== undefined)}
<div class="mt-2 ml-2 flex-between">
<div class="mt-2 ml-2 flex-between flex-no-shrink">
{#if $selectionStore.length > 0}
<div class="item-box">
{$selectionStore.length} items
<Label label={view.string.NumberItems} params={{ count: $selectionStore.length }} />
</div>
{:else if $focusStore.focus !== undefined}
<div class="item-box">
@ -205,15 +205,17 @@
objectId={$focusStore.focus._id}
_class={$focusStore.focus._class}
value={$focusStore.focus}
props={{ inline: true }}
disabled
/>
</div>
{/if}
{#if activeAction && activeAction?.actionPopup !== undefined}
<div class="mt-2 mb-2 mr-2">
<div class="mr-2">
<Button
icon={IconArrowLeft}
label={ui.string.Back}
kind={'ghost'}
size={'small'}
on:click={() => {
activeAction = undefined
}}
@ -230,7 +232,8 @@
...activeAction.actionProps,
value: getSelection($focusStore, $selectionStore),
width: 'full',
size: 'medium'
size: 'medium',
embedded: true
}}
on:close={async () => {
activeAction = undefined
@ -305,6 +308,7 @@
</div>
</div>
{/if}
<div class="menu-space" />
</div>
<style lang="scss">

View File

@ -53,6 +53,6 @@
$: if (object !== undefined) getHref(object)
</script>
<NavLink {disabled} {onClick} {noUnderline} {inline} {shrink} {href} {colorInherit} {accent} {noOverflow}
><slot /></NavLink
>
<NavLink {disabled} {onClick} {noUnderline} {inline} {shrink} {href} {colorInherit} {accent} {noOverflow}>
<slot />
</NavLink>

View File

@ -26,6 +26,9 @@
export let accent: boolean = false
export let shouldShowAvatar: boolean = true
export let noUnderline: boolean = false
export let disabled: boolean = false
export let shouldShowName: boolean = true
export let shrink: number = 0
const client = getClient()
let presenter: AttributeModel | undefined
@ -73,7 +76,10 @@
{inline}
{accent}
{shouldShowAvatar}
{shouldShowName}
{noUnderline}
{disabled}
{shrink}
{...props}
on:accent-color
on:close

View File

@ -17,6 +17,24 @@
import { ObjectPresenter } from '..'
export let value: Ref<Space>
export let inline: boolean = false
export let accent: boolean = false
export let shouldShowAvatar: boolean = true
export let noUnderline: boolean = false
export let disabled: boolean = false
export let shouldShowName: boolean = true
export let shrink: number = 0
</script>
<ObjectPresenter objectId={value} _class={core.class.Space} on:accent-color />
<ObjectPresenter
objectId={value}
_class={core.class.Space}
{shouldShowAvatar}
{shouldShowName}
{disabled}
{inline}
{noUnderline}
{shrink}
{accent}
on:accent-color
/>

View File

@ -30,6 +30,7 @@
export let placeholder: IntlString | undefined
export let width: 'medium' | 'large' | 'full' = 'medium'
export let size: 'small' | 'medium' | 'large' = 'small'
export let embedded: boolean = false
const dispatch = createEventDispatcher()
const client = getClient()
@ -133,6 +134,7 @@
searchable
{width}
{size}
{embedded}
on:changeContent
/>
{:else if _class !== undefined}
@ -149,6 +151,7 @@
placeholder={placeholder ?? view.string.Filter}
{width}
{size}
{embedded}
on:changeContent
>
<svelte:fragment slot="item" let:item>

View File

@ -96,6 +96,7 @@
class:collapsed
class:subLevel={level !== 0}
class:lastCat
class:cursor-pointer={items.length > 0}
on:focus={() => {
mouseOver = true
}}
@ -131,6 +132,7 @@
kind={'list-header'}
colorInherit={!$themeStore.dark && level === 0}
accent={level === 0}
disabled
on:accent-color={(evt) => {
accentColor = evt.detail
}}

View File

@ -98,7 +98,8 @@ export default mergeIds(viewId, view, {
ChooseIcon: '' as IntlString,
IconColor: '' as IntlString,
IconCategory: '' as IntlString,
EmojiCategory: '' as IntlString
EmojiCategory: '' as IntlString,
NumberItems: '' as IntlString
},
function: {
CreateDocMiddleware: '' as Resource<PresentationMiddlewareCreator>

View File

@ -723,7 +723,7 @@
{/if}
</NavFooter>
</div>
<Separator name={'workbench'} index={0} />
<Separator name={'workbench'} index={0} color={'var(--theme-navpanel-border)'} />
{/if}
<div
class="antiPanel-component antiComponent"