UBER-177: fixed Filter pop-ups (#3225)

Signed-off-by: Alexander Platov <sas_lord@mail.ru>
This commit is contained in:
Alexander Platov 2023-05-20 23:01:09 -07:00 committed by GitHub
parent c0bb68be9e
commit 78034e6a00
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 204 additions and 207 deletions

View File

@ -745,7 +745,7 @@
.list-container .datetime-button, .list-container .datetime-button,
.list-container .datetime-button:hover { .list-container .datetime-button:hover {
background-color: var(--theme-list-button-color) !important; background-color: var(--theme-list-button-color) !important;
.icon { .icon, .btn-icon {
margin-right: .5rem; margin-right: .5rem;
color: var(--theme-halfcontent-color) !important; color: var(--theme-halfcontent-color) !important;
} }

View File

@ -48,11 +48,12 @@
max-width: 40rem !important; max-width: 40rem !important;
} }
.header { .header {
margin-bottom: .5rem;
padding: .5rem; padding: .5rem;
border-bottom: 1px solid var(--theme-popup-divider);
&:not(.no-border) {
&.no-border { border-bottom-color: transparent; } margin-bottom: .5rem;
border-bottom: 1px solid var(--theme-popup-divider);
}
.clear-btn { .clear-btn {
display: flex; display: flex;
justify-content: center; justify-content: center;
@ -345,11 +346,13 @@
align-items: center; align-items: center;
flex-shrink: 0; flex-shrink: 0;
justify-content: flex-start; justify-content: flex-start;
margin: 0 .5rem;
padding: .25rem .5rem; padding: .25rem .5rem;
min-width: 0; min-width: 0;
min-height: 2.25rem; min-height: 2.25rem;
text-align: left; text-align: left;
color: var(--theme-caption-color); color: var(--theme-caption-color);
border-radius: .25rem;
outline: none; outline: none;
cursor: pointer; cursor: pointer;

View File

@ -153,11 +153,7 @@
> >
<svelte:fragment slot="item" let:item={itemId}> <svelte:fragment slot="item" let:item={itemId}>
{@const item = filteredObjects[itemId]} {@const item = filteredObjects[itemId]}
<button <button class="menu-item withList w-full" on:click={() => dispatch('close', item.id)}>
class="menu-item withList w-full"
class:selected={item.isSelected}
on:click={() => dispatch('close', item.id)}
>
<div class="flex-row-center flex-grow pointer-events-none"> <div class="flex-row-center flex-grow pointer-events-none">
{#if item.component} {#if item.component}
<div class="flex-grow clear-mins"><svelte:component this={item.component} {...item.props} /></div> <div class="flex-grow clear-mins"><svelte:component this={item.component} {...item.props} /></div>

View File

@ -70,6 +70,7 @@
"DM": "Direct message", "DM": "Direct message",
"DMNotification": "Sent you a message", "DMNotification": "Sent you a message",
"ConfigLabel": "Chat", "ConfigLabel": "Chat",
"ConfigDescription": "Extension to perform text communications" "ConfigDescription": "Extension to perform text communications",
"LastMessage": "Last message"
} }
} }

View File

@ -70,6 +70,7 @@
"DM": "Личное сообщение", "DM": "Личное сообщение",
"DMNotification": "Отправил сообщение", "DMNotification": "Отправил сообщение",
"ConfigLabel": "Чат", "ConfigLabel": "Чат",
"ConfigDescription": "Расширение для текстовых переписок" "ConfigDescription": "Расширение для текстовых переписок",
"LastMessage": "Последнее сообщение"
} }
} }

View File

@ -15,7 +15,7 @@
<script lang="ts"> <script lang="ts">
import { ChannelProvider } from '@hcengineering/contact' import { ChannelProvider } from '@hcengineering/contact'
import { Ref } from '@hcengineering/core' import { Ref } from '@hcengineering/core'
import { CheckBox, Icon, Label, resizeObserver } from '@hcengineering/ui' import { IconCheck, Icon, Label, resizeObserver } from '@hcengineering/ui'
import { Filter } from '@hcengineering/view' import { Filter } from '@hcengineering/view'
import { FILTER_DEBOUNCE_MS, FilterQuery, sortFilterValues } from '@hcengineering/view-resources' import { FILTER_DEBOUNCE_MS, FilterQuery, sortFilterValues } from '@hcengineering/view-resources'
import { createEventDispatcher } from 'svelte' import { createEventDispatcher } from 'svelte'
@ -65,28 +65,28 @@
</script> </script>
<div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}> <div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}>
<div class="menu-space" />
<div class="scroll"> <div class="scroll">
<div class="box"> <div class="box">
{#each sortFilterValues($channelProviders, (v) => isSelected(v, selected)) as element} {#each sortFilterValues($channelProviders, (v) => isSelected(v, selected)) as element}
<button <button
class="menu-item" class="menu-item no-focus flex-row-center content-pointer-events-none"
on:click={() => { on:click={() => {
handleFilterToggle(element) handleFilterToggle(element)
}} }}
> >
<div class="flex-between w-full"> {#if element.icon}
<div class="flex"> <div class="icon"><Icon icon={element.icon} size={'small'} /></div>
<div class="check pointer-events-none"> {/if}
<CheckBox checked={isSelected(element, selected)} primary /> <span class="overflow-label label flex-grow"><Label label={element.label} /></span>
</div> <div class="check">
{#if element.icon} {#if isSelected(element, selected)}
<span class="mr-2"><Icon icon={element.icon} size="inline" /></span> <Icon icon={IconCheck} size={'small'} />
{/if} {/if}
<Label label={element.label} />
</div>
</div> </div>
</button> </button>
{/each} {/each}
</div> </div>
</div> </div>
<div class="menu-space" />
</div> </div>

View File

@ -17,11 +17,20 @@
import core, { Doc, FindResult, getObjectValue, Ref, SortingOrder, Space } from '@hcengineering/core' import core, { Doc, FindResult, getObjectValue, Ref, SortingOrder, Space } from '@hcengineering/core'
import { translate } from '@hcengineering/platform' import { translate } from '@hcengineering/platform'
import presentation, { getClient } from '@hcengineering/presentation' import presentation, { getClient } from '@hcengineering/presentation'
import ui, { addNotification, deviceOptionsStore, Icon, IconCheck, Loading, resizeObserver } from '@hcengineering/ui' import ui, {
addNotification,
deviceOptionsStore,
Icon,
IconCheck,
Loading,
resizeObserver,
EditWithIcon,
IconSearch
} from '@hcengineering/ui'
import { Filter } from '@hcengineering/view' import { Filter } from '@hcengineering/view'
import { FILTER_DEBOUNCE_MS, FilterRemovedNotification, sortFilterValues } from '@hcengineering/view-resources' import { FILTER_DEBOUNCE_MS, FilterRemovedNotification, sortFilterValues } from '@hcengineering/view-resources'
import view from '@hcengineering/view-resources/src/plugin' import view from '@hcengineering/view-resources/src/plugin'
import { createEventDispatcher, onMount } from 'svelte' import { createEventDispatcher } from 'svelte'
import EmployeePresenter from './EmployeePresenter.svelte' import EmployeePresenter from './EmployeePresenter.svelte'
export let filter: Filter export let filter: Filter
@ -113,15 +122,6 @@
} }
let search: string = '' let search: string = ''
let phTraslate: string = ''
let searchInput: HTMLInputElement
$: translate(presentation.string.Search, {}).then((res) => {
phTraslate = res
})
onMount(() => {
if (searchInput && !$deviceOptionsStore.isMobile) searchInput.focus()
})
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
$: getValues(search) $: getValues(search)
@ -129,14 +129,16 @@
<div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}> <div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}>
<div class="header"> <div class="header">
<input <EditWithIcon
bind:this={searchInput} icon={IconSearch}
type="text" size={'large'}
width={'100%'}
focus={!$deviceOptionsStore.isMobile}
bind:value={search} bind:value={search}
placeholder={presentation.string.Search}
on:change={() => { on:change={() => {
getValues(search) getValues(search)
}} }}
placeholder={phTraslate}
/> />
</div> </div>
<div class="scroll"> <div class="scroll">
@ -146,24 +148,23 @@
{:else} {:else}
{#each sortFilterValues(values, (v) => isSelected(v, filter.value)) as value} {#each sortFilterValues(values, (v) => isSelected(v, filter.value)) as value}
<button <button
class="menu-item no-focus" class="menu-item no-focus flex-row-center"
on:click={() => { on:click={() => {
handleFilterToggle(value) handleFilterToggle(value)
}} }}
> >
<div class="flex-between w-full"> <div class="clear-mins flex-grow">
<div class="flex-row-center"> <EmployeePresenter {value} shouldShowPlaceholder defaultName={ui.string.NotSelected} disabled />
<EmployeePresenter {value} shouldShowPlaceholder defaultName={ui.string.NotSelected} disabled /> </div>
</div> <div class="check pointer-events-none">
<div class="pointer-events-none"> {#if isSelected(value, filter.value)}
{#if isSelected(value, filter.value)} <Icon icon={IconCheck} size={'small'} />
<Icon icon={IconCheck} size={'small'} /> {/if}
{/if}
</div>
</div> </div>
</button> </button>
{/each} {/each}
{/if} {/if}
</div> </div>
</div> </div>
<div class="menu-space" />
</div> </div>

View File

@ -27,12 +27,12 @@
</script> </script>
{#if value} {#if value}
<DocNavLink {disabled} object={value} {inline} component={recruit.component.EditVacancy}> <DocNavLink {disabled} object={value} {inline} noUnderline={disabled} component={recruit.component.EditVacancy}>
<div class="flex-presenter" class:inline-presenter={inline} use:tooltip={{ label: getEmbeddedLabel(value.name) }}> <div class="flex-presenter" class:inline-presenter={inline} use:tooltip={{ label: getEmbeddedLabel(value.name) }}>
{#if !inline} {#if !inline}
<div class="icon"><Icon icon={recruit.icon.Vacancy} size={'small'} /></div> <div class="icon"><Icon icon={recruit.icon.Vacancy} size={'small'} /></div>
{/if} {/if}
<span class="label">{value.name}</span> <span class="label" class:no-underline={disabled}>{value.name}</span>
</div> </div>
</DocNavLink> </DocNavLink>
{/if} {/if}

View File

@ -14,13 +14,14 @@
--> -->
<script lang="ts"> <script lang="ts">
import { Class, Doc, FindResult, Ref } from '@hcengineering/core' import { Class, Doc, FindResult, Ref } from '@hcengineering/core'
import { translate } from '@hcengineering/platform'
import presentation, { getClient } from '@hcengineering/presentation' import presentation, { getClient } from '@hcengineering/presentation'
import { TagCategory, TagElement } from '@hcengineering/tags' import { TagCategory, TagElement } from '@hcengineering/tags'
import { import {
Button, Button,
Icon, Icon,
IconCheck, IconCheck,
IconSearch,
EditWithIcon,
Label, Label,
Loading, Loading,
deviceOptionsStore, deviceOptionsStore,
@ -31,7 +32,7 @@
} from '@hcengineering/ui' } from '@hcengineering/ui'
import { Filter } from '@hcengineering/view' import { Filter } from '@hcengineering/view'
import { FILTER_DEBOUNCE_MS, FilterQuery, sortFilterValues } from '@hcengineering/view-resources' import { FILTER_DEBOUNCE_MS, FilterQuery, sortFilterValues } from '@hcengineering/view-resources'
import { createEventDispatcher, onMount } from 'svelte' import { createEventDispatcher } from 'svelte'
import tags from '../plugin' import tags from '../plugin'
import { tagLevel } from '../utils' import { tagLevel } from '../utils'
import WeightPopup from './WeightPopup.svelte' import WeightPopup from './WeightPopup.svelte'
@ -76,15 +77,6 @@
} }
let search: string = '' let search: string = ''
let phTraslate: string = ''
let searchInput: HTMLInputElement
$: translate(presentation.string.Search, {}).then((res) => {
phTraslate = res
})
onMount(() => {
if (searchInput && !$deviceOptionsStore.isMobile) searchInput.focus()
})
const toggleGroup = (ev: MouseEvent): void => { const toggleGroup = (ev: MouseEvent): void => {
const el: HTMLElement = ev.currentTarget as HTMLElement const el: HTMLElement = ev.currentTarget as HTMLElement
@ -137,18 +129,20 @@
<div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}> <div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}>
<div class="header"> <div class="header">
<input <EditWithIcon
bind:this={searchInput} icon={IconSearch}
type="text" size={'large'}
width={'100%'}
focus={!$deviceOptionsStore.isMobile}
bind:value={search} bind:value={search}
placeholder={presentation.string.Search}
on:change={() => { on:change={() => {
getValues(search) getValues(search)
}} }}
placeholder={phTraslate}
/> />
{#if schema !== '0'} {#if schema !== '0'}
<div class="flex-row-center flex-between flex-grow p-1"> <div class="flex-between w-full mt-2">
<Label label={tags.string.Weight} /> <span class="overflow-label pl-2 mr-2"><Label label={tags.string.Weight} /></span>
<Button <Button
label={tagLevelLabel} label={tagLevelLabel}
icon={tagLevelIcon} icon={tagLevelIcon}
@ -170,9 +164,10 @@
{#if objectsPromise} {#if objectsPromise}
<Loading /> <Loading />
{:else} {:else}
{#each categories as cat} {#each categories as cat, i}
{@const values = objects.filter((el) => el.category === cat._id)} {@const values = objects.filter((el) => el.category === cat._id)}
{#if values.length > 0} {#if values.length > 0}
{#if i > 0}<div class="menu-separator" />{/if}
<div class="sticky-wrapper"> <div class="sticky-wrapper">
<button <button
class="menu-group__header" class="menu-group__header"
@ -198,21 +193,17 @@
<div class="menu-group"> <div class="menu-group">
{#each sortFilterValues(values, isSelected) as element} {#each sortFilterValues(values, isSelected) as element}
<button <button
class="menu-item" class="menu-item no-focus flex-row-center"
on:click={() => { on:click={() => {
handleFilterToggle(element) handleFilterToggle(element)
}} }}
> >
<div class="flex-between w-full"> <div class="tag" style="background-color: {getPlatformColor(element.color)};" />
<div class="flex"> <span class="overflow-label label flex-grow">{element.title}</span>
<div class="tag" style="background-color: {getPlatformColor(element.color)};" /> <div class="check pointer-events-none">
{element.title} {#if isSelected(element)}
</div> <Icon icon={IconCheck} size={'small'} />
<div class="pointer-events-none"> {/if}
{#if isSelected(element)}
<Icon icon={IconCheck} size={'small'} />
{/if}
</div>
</div> </div>
</button> </button>
{/each} {/each}
@ -223,6 +214,7 @@
{/if} {/if}
</div> </div>
</div> </div>
<div class="menu-space" />
</div> </div>
<style> <style>

View File

@ -13,7 +13,7 @@
// limitations under the License. // limitations under the License.
--> -->
<script lang="ts"> <script lang="ts">
import { Button, resizeObserver } from '@hcengineering/ui' import { resizeObserver, Icon, IconCheck, Label } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte' import { createEventDispatcher } from 'svelte'
import tags from '../plugin' import tags from '../plugin'
import { tagLevel } from '../utils' import { tagLevel } from '../utils'
@ -27,34 +27,36 @@
</script> </script>
<div class="selectPopup max-width-40" use:resizeObserver={() => dispatch('changeContent')}> <div class="selectPopup max-width-40" use:resizeObserver={() => dispatch('changeContent')}>
<div class="header no-border p-3"> <div class="menu-space" />
{#each labels as l, i} <div class="scroll">
<div class="flex gap-2 p-1"> <div class="box">
{#each labels as l, i}
{#if schema === '9'} {#if schema === '9'}
{#each Object.entries(tagLevel) as k, j} {#each Object.entries(tagLevel) as k, j}
{@const valueK = i * 3 + j} {@const valueK = i * 3 + j}
<Button <button class="menu-item flex-row-center" on:click={() => dispatch('close', valueK)}>
label={l} <div class="icon"><Icon icon={k[1]} size={'small'} /></div>
icon={k[1]} <span class="overflow-label label flex-grow"><Label label={l} /></span>
size={'small'} <div class="check pointer-events-none">
justify={'left'} {#if value === valueK}
selected={value === valueK} <Icon icon={IconCheck} size={'small'} />
on:click={() => dispatch('close', valueK)} {/if}
width={'8rem'} </div>
/> </button>
{/each} {/each}
{:else} {:else}
{@const valueK = i * 3} {@const valueK = i * 3}
<Button <button class="menu-item flex-row-center" on:click={() => dispatch('close', valueK)}>
label={l} <span class="overflow-label label flex-grow"><Label label={l} /></span>
size={'small'} <div class="check pointer-events-none">
justify={'left'} {#if value === valueK}
selected={value === valueK} <Icon icon={IconCheck} size={'small'} />
on:click={() => dispatch('close', valueK)} {/if}
width={'8rem'} </div>
/> </button>
{/if} {/if}
</div> {/each}
{/each} </div>
</div> </div>
<div class="menu-space" />
</div> </div>

View File

@ -23,6 +23,8 @@
export let inline: boolean = false export let inline: boolean = false
export let colorInherit: boolean = false export let colorInherit: boolean = false
export let accent: boolean = false export let accent: boolean = false
export let disabled: boolean = false
export let oneLine: boolean = false
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
@ -46,7 +48,7 @@
{#if shouldShowAvatar} {#if shouldShowAvatar}
<div class="state-container" class:inline style="background-color: {fill}" /> <div class="state-container" class:inline style="background-color: {fill}" />
{/if} {/if}
<span class="label nowrap">{value.name}</span> <span class="overflow-label label" class:nowrap={oneLine} class:no-underline={disabled}>{value.name}</span>
</div> </div>
{/if} {/if}

View File

@ -14,13 +14,21 @@
--> -->
<script lang="ts"> <script lang="ts">
import { DocumentQuery, FindResult, Ref, SortingOrder } from '@hcengineering/core' import { DocumentQuery, FindResult, Ref, SortingOrder } from '@hcengineering/core'
import { translate } from '@hcengineering/platform'
import presentation, { getClient } from '@hcengineering/presentation' import presentation, { getClient } from '@hcengineering/presentation'
import { Project, Milestone, MilestoneStatus } from '@hcengineering/tracker' import { Project, Milestone, MilestoneStatus } from '@hcengineering/tracker'
import ui, { CheckBox, Icon, Label, Loading, deviceOptionsStore, resizeObserver } from '@hcengineering/ui' import ui, {
IconCheck,
Icon,
Label,
Loading,
deviceOptionsStore,
resizeObserver,
EditWithIcon,
IconSearch
} from '@hcengineering/ui'
import { FILTER_DEBOUNCE_MS, sortFilterValues } from '@hcengineering/view-resources' import { FILTER_DEBOUNCE_MS, sortFilterValues } from '@hcengineering/view-resources'
import view, { Filter } from '@hcengineering/view' import view, { Filter } from '@hcengineering/view'
import { createEventDispatcher, onMount } from 'svelte' import { createEventDispatcher } from 'svelte'
import tracker from '../../plugin' import tracker from '../../plugin'
import { milestoneStatusAssets } from '../../types' import { milestoneStatusAssets } from '../../types'
import MilestoneTitlePresenter from './MilestoneTitlePresenter.svelte' import MilestoneTitlePresenter from './MilestoneTitlePresenter.svelte'
@ -34,11 +42,6 @@
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
let search: string = '' let search: string = ''
let phTraslate: string = ''
let searchInput: HTMLInputElement
$: translate(presentation.string.Search, {}).then((res) => {
phTraslate = res
})
let values: Milestone[] = [] let values: Milestone[] = []
let objectsPromise: Promise<FindResult<Milestone>> | undefined = undefined let objectsPromise: Promise<FindResult<Milestone>> | undefined = undefined
@ -110,23 +113,21 @@
return res return res
} }
onMount(() => {
if (searchInput && !$deviceOptionsStore.isMobile) searchInput.focus()
})
getValues(search) getValues(search)
</script> </script>
<div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}> <div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}>
<div class="header"> <div class="header">
<input <EditWithIcon
bind:this={searchInput} icon={IconSearch}
type="text" size={'large'}
width={'100%'}
focus={!$deviceOptionsStore.isMobile}
bind:value={search} bind:value={search}
placeholder={presentation.string.Search}
on:change={() => { on:change={() => {
getValues(search) getValues(search)
}} }}
placeholder={phTraslate}
/> />
</div> </div>
<div class="scroll"> <div class="scroll">
@ -135,41 +136,46 @@
<Loading /> <Loading />
{:else} {:else}
<button <button
class="menu-item" class="menu-item no-focus flex-row-center"
on:click={() => { on:click={() => {
handleFilterToggle(undefined) handleFilterToggle(undefined)
}} }}
> >
<div class="flex clear-mins"> <div class="overflow-label flex-grow">
<div class="check pointer-events-none">
<CheckBox checked={isSelected(undefined, selectedValues)} primary />
</div>
<Label label={ui.string.NotSelected} /> <Label label={ui.string.NotSelected} />
</div> </div>
<div class="check pointer-events-none">
{#if isSelected(undefined, selectedValues)}
<Icon icon={IconCheck} size={'small'} />
{/if}
</div>
</button> </button>
{#each getStatuses() as group} {#each getStatuses() as group}
{@const status = milestoneStatusAssets[group]} {@const status = milestoneStatusAssets[group]}
{@const items = getStatusItem(group, values)} {@const items = getStatusItem(group, values)}
{#if items.length > 0} {#if items.length > 0}
<div class="flex-row-center p-1"> <div class="menu-separator" />
<Icon icon={status.icon} size={'small'} /> <div class="menu-group__header">
<div class="ml-2"> <div class="flex-row-center gap-2">
<Label label={status.label} /> <Icon icon={status.icon} size={'small'} />
<span class="overflow-label"><Label label={status.label} /></span>
</div> </div>
</div> </div>
{#each sortFilterValues(items, (v) => isSelected(v._id, selectedValues)) as doc} {#each sortFilterValues(items, (v) => isSelected(v._id, selectedValues)) as doc}
<button <button
class="menu-item" class="menu-item no-focus flex-row-center"
on:click={() => { on:click={() => {
handleFilterToggle(doc._id) handleFilterToggle(doc._id)
}} }}
> >
<div class="flex clear-mins"> <div class="flex-grow clear-mins">
<div class="check pointer-events-none">
<CheckBox checked={isSelected(doc._id, selectedValues)} primary />
</div>
<MilestoneTitlePresenter value={doc} /> <MilestoneTitlePresenter value={doc} />
</div> </div>
<div class="check pointer-events-none">
{#if isSelected(doc._id, selectedValues)}
<Icon icon={IconCheck} size={'small'} />
{/if}
</div>
</button> </button>
{/each} {/each}
{/if} {/if}
@ -177,4 +183,5 @@
{/if} {/if}
</div> </div>
</div> </div>
<div class="menu-space" />
</div> </div>

View File

@ -265,6 +265,7 @@
</script> </script>
<div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}> <div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}>
<div class="menu-space" />
<Scroller> <Scroller>
{#if nestedFrom} {#if nestedFrom}
<!-- svelte-ignore a11y-mouse-events-have-key-events --> <!-- svelte-ignore a11y-mouse-events-have-key-events -->
@ -320,15 +321,9 @@
</button> </button>
{/if} {/if}
{#if nextDiffCat(types, i)} {#if nextDiffCat(types, i)}
<div class="divider" /> <div class="menu-separator" />
{/if} {/if}
{/each} {/each}
</Scroller> </Scroller>
<div class="menu-space" />
</div> </div>
<style lang="scss">
.divider {
height: 1px;
background-color: var(--theme-popup-divider);
}
</style>

View File

@ -20,13 +20,15 @@
addNotification, addNotification,
Icon, Icon,
IconCheck, IconCheck,
IconSearch,
deviceOptionsStore, deviceOptionsStore,
Label, Label,
Loading, Loading,
resizeObserver resizeObserver,
EditWithIcon
} from '@hcengineering/ui' } from '@hcengineering/ui'
import { Filter } from '@hcengineering/view' import { Filter } from '@hcengineering/view'
import { createEventDispatcher, onMount } from 'svelte' import { createEventDispatcher } from 'svelte'
import view from '../../plugin' import view from '../../plugin'
import { FILTER_DEBOUNCE_MS, sortFilterValues } from '../../filter' import { FILTER_DEBOUNCE_MS, sortFilterValues } from '../../filter'
import { buildConfigLookup, getPresenter } from '../../utils' import { buildConfigLookup, getPresenter } from '../../utils'
@ -152,15 +154,6 @@
} }
let search: string = '' let search: string = ''
let phTraslate: string = ''
let searchInput: HTMLInputElement
$: translate(presentation.string.Search, {}).then((res) => {
phTraslate = res
})
onMount(() => {
if (searchInput && !$deviceOptionsStore.isMobile) searchInput.focus()
})
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
$: if (targetClass) getValues(search) $: if (targetClass) getValues(search)
@ -169,16 +162,20 @@
<div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}> <div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}>
{#if clazz.sortingKey} {#if clazz.sortingKey}
<div class="header"> <div class="header">
<input <EditWithIcon
bind:this={searchInput} icon={IconSearch}
type="text" size={'large'}
width={'100%'}
focus={!$deviceOptionsStore.isMobile}
bind:value={search} bind:value={search}
placeholder={presentation.string.Search}
on:change={() => { on:change={() => {
getValues(search) getValues(search)
}} }}
placeholder={phTraslate}
/> />
</div> </div>
{:else}
<div class="menu-space" />
{/if} {/if}
<div class="scroll"> <div class="scroll">
<div class="box"> <div class="box">
@ -188,7 +185,7 @@
{:else} {:else}
{#each sortFilterValues(values, (v) => isSelected(v, filter.value)) as value} {#each sortFilterValues(values, (v) => isSelected(v, filter.value)) as value}
<button <button
class="menu-item no-focus" class="menu-item no-focus content-pointer-events-none"
on:click={() => { on:click={() => {
handleFilterToggle(value) handleFilterToggle(value)
}} }}
@ -215,4 +212,5 @@
{/await} {/await}
</div> </div>
</div> </div>
<div class="menu-space" />
</div> </div>

View File

@ -13,10 +13,9 @@
// limitations under the License. // limitations under the License.
--> -->
<script lang="ts"> <script lang="ts">
import { translate } from '@hcengineering/platform' import { Button, resizeObserver, deviceOptionsStore, EditWithIcon, IconSearch } from '@hcengineering/ui'
import { Button, resizeObserver, deviceOptionsStore } from '@hcengineering/ui'
import { Filter } from '@hcengineering/view' import { Filter } from '@hcengineering/view'
import { onMount, createEventDispatcher } from 'svelte' import { createEventDispatcher } from 'svelte'
import view from '../../plugin' import view from '../../plugin'
export let filter: Filter export let filter: Filter
@ -24,9 +23,7 @@
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
let searchInput: HTMLInputElement
let search = filter.value[0] ?? '' let search = filter.value[0] ?? ''
let phTraslate = ''
filter.modes = [view.filter.FilterContains] filter.modes = [view.filter.FilterContains]
filter.mode ??= filter.modes[0] filter.mode ??= filter.modes[0]
@ -49,19 +46,19 @@
onChange(filter) onChange(filter)
dispatch('close') dispatch('close')
} }
$: translate(filter.key.label, {}).then((res) => {
phTraslate = res
})
onMount(() => {
if (searchInput && !$deviceOptionsStore.isMobile) searchInput.focus()
})
</script> </script>
<div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')} on:keydown={onKeyDown}> <div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')} on:keydown={onKeyDown}>
<div class="header"> <div class="header no-border">
<input bind:this={searchInput} bind:value={search} type="text" placeholder={phTraslate} /> <EditWithIcon
icon={IconSearch}
size={'large'}
width={'100%'}
focus={!$deviceOptionsStore.isMobile}
bind:value={search}
placeholder={filter.key.label}
on:change
/>
</div> </div>
<Button shape="filter" label={view.string.Apply} on:click={save} /> <Button shape="filter" label={view.string.Apply} on:click={save} />
</div> </div>

View File

@ -14,11 +14,19 @@
--> -->
<script lang="ts"> <script lang="ts">
import core, { Class, Doc, FindResult, getObjectValue, Ref, SortingOrder, Space } from '@hcengineering/core' import core, { Class, Doc, FindResult, getObjectValue, Ref, SortingOrder, Space } from '@hcengineering/core'
import { translate } from '@hcengineering/platform'
import presentation, { getClient } from '@hcengineering/presentation' import presentation, { getClient } from '@hcengineering/presentation'
import ui, { Icon, IconCheck, Label, Loading, resizeObserver, deviceOptionsStore } from '@hcengineering/ui' import ui, {
EditWithIcon,
Icon,
IconSearch,
IconCheck,
Label,
Loading,
resizeObserver,
deviceOptionsStore
} from '@hcengineering/ui'
import { Filter } from '@hcengineering/view' import { Filter } from '@hcengineering/view'
import { onMount, createEventDispatcher } from 'svelte' import { createEventDispatcher } from 'svelte'
import { getPresenter } from '../../utils' import { getPresenter } from '../../utils'
import { FILTER_DEBOUNCE_MS, sortFilterValues } from '../../filter' import { FILTER_DEBOUNCE_MS, sortFilterValues } from '../../filter'
import view from '../../plugin' import view from '../../plugin'
@ -127,34 +135,29 @@
} }
let search: string = '' let search: string = ''
let phTraslate: string = ''
let searchInput: HTMLInputElement
$: translate(presentation.string.Search, {}).then((res) => {
phTraslate = res
})
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
onMount(() => {
if (searchInput && !$deviceOptionsStore.isMobile) searchInput.focus()
})
getValues(search) getValues(search)
</script> </script>
<div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}> <div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}>
{#if isSearchable} {#if isSearchable}
<div class="header"> <div class="header">
<input <EditWithIcon
bind:this={searchInput} icon={IconSearch}
type="text" size={'large'}
width={'100%'}
focus={!$deviceOptionsStore.isMobile}
bind:value={search} bind:value={search}
placeholder={presentation.string.Search}
on:change={() => { on:change={() => {
getValues(search) getValues(search)
}} }}
placeholder={phTraslate}
/> />
</div> </div>
{:else}
<div class="menu-space" />
{/if} {/if}
<div class="scroll"> <div class="scroll">
<div class="box"> <div class="box">
@ -165,29 +168,27 @@
{#each sortFilterValues([...values.keys()], (v) => isSelected(v, selectedValues)) as value} {#each sortFilterValues([...values.keys()], (v) => isSelected(v, selectedValues)) as value}
{@const realValue = [...(realValues.get(value) ?? [])][0]} {@const realValue = [...(realValues.get(value) ?? [])][0]}
<button <button
class="menu-item no-focus" class="menu-item no-focus content-pointer-events-none"
on:click={() => { on:click={() => {
handleFilterToggle(value) handleFilterToggle(value)
}} }}
> >
<div class="flex-between w-full"> {#if value !== undefined}
<div class="flex-row-center"> <div class="clear-mins flex-grow">
{#if value !== undefined} <svelte:component
<svelte:component this={attribute.presenter}
this={attribute.presenter} value={typeof value === 'string' ? realValue : value}
value={typeof value === 'string' ? realValue : value} {...attribute.props}
{...attribute.props} oneLine
oneLine />
/>
{:else}
<Label label={ui.string.NotSelected} />
{/if}
</div>
<div class="pointer-events-none">
{#if isSelected(value, selectedValues)}
<Icon icon={IconCheck} size={'small'} />
{/if}
</div> </div>
{:else}
<span class="overflow-label flex-grow"><Label label={ui.string.NotSelected} /></span>
{/if}
<div class="check pointer-events-none">
{#if isSelected(value, selectedValues)}
<Icon icon={IconCheck} size={'small'} />
{/if}
</div> </div>
</button> </button>
{/each} {/each}
@ -195,4 +196,5 @@
{/await} {/await}
</div> </div>
</div> </div>
<div class="menu-space" />
</div> </div>