mirror of
https://github.com/hcengineering/platform.git
synced 2025-05-03 05:43:24 +00:00
Update UserBoxList layout. Fix AccountPopup. (#1397)
This commit is contained in:
parent
942295b26b
commit
b204009eab
@ -14,6 +14,7 @@
|
||||
"Members": "Members",
|
||||
"Search": "Search...",
|
||||
"Unassigned": "Unassigned",
|
||||
"CreateMore": "Create more"
|
||||
"CreateMore": "Create more",
|
||||
"NumberMembers": "{lenght, plural, =0 {no members} =1 {1 member} other {# members}}"
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@
|
||||
"Members": "Участники",
|
||||
"Search": "Поиск...",
|
||||
"Unassigned": "Не назначен",
|
||||
"CreateMore": "Создать еще"
|
||||
"CreateMore": "Создать еще",
|
||||
"NumberMembers": "{lenght, plural, =0 {нет участников} =1 {1 участик} other {# участника}}"
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@
|
||||
|
||||
export let avatar: string | null | undefined = undefined
|
||||
export let direct: Blob | undefined = undefined
|
||||
export let size: 'x-small' | 'small' | 'medium' | 'large' | 'x-large'
|
||||
export let size: 'inline' | 'x-small' | 'small' | 'medium' | 'large' | 'x-large'
|
||||
|
||||
let url: string | undefined
|
||||
$: if (direct !== undefined) {
|
||||
@ -50,7 +50,7 @@
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
background-color: var(--popup-bg-hover);
|
||||
background-color: var(--avatar-bg-color);
|
||||
border-radius: 50%;
|
||||
pointer-events: none;
|
||||
|
||||
@ -61,6 +61,10 @@
|
||||
&.no-img { border-color: transparent; }
|
||||
}
|
||||
|
||||
.ava-inline {
|
||||
width: .875rem; // 24
|
||||
height: .875rem;
|
||||
}
|
||||
.ava-x-small {
|
||||
width: 1.5rem; // 24
|
||||
height: 1.5rem;
|
||||
@ -92,6 +96,7 @@
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.ava-inline .ava-mask, .ava-inline.no-img,
|
||||
.ava-x-small .ava-mask, .ava-x-small.no-img,
|
||||
.ava-small .ava-mask, .ava-small.no-img,
|
||||
.ava-medium .ava-mask, .ava-medium.no-img { border-style: none; }
|
||||
|
53
packages/presentation/src/components/CombineAvatars.svelte
Normal file
53
packages/presentation/src/components/CombineAvatars.svelte
Normal file
@ -0,0 +1,53 @@
|
||||
<!--
|
||||
// Copyright © 2020 Anticrm Platform Contributors.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import type { Class, Doc, Ref } from '@anticrm/core'
|
||||
import { createQuery } from '../utils'
|
||||
import { Person } from '@anticrm/contact'
|
||||
import Avatar from './Avatar.svelte'
|
||||
|
||||
export let _class: Ref<Class<Doc>>
|
||||
export let items: Ref<Person>[] = []
|
||||
export let size: 'inline' | 'x-small' | 'small' | 'medium' | 'large' | 'x-large'
|
||||
export let limit: number = 3
|
||||
|
||||
let persons: Person[] = []
|
||||
const query = createQuery()
|
||||
$: query.query<Person>(_class, { _id: { $in: items } }, result => { persons = result }, { limit })
|
||||
</script>
|
||||
|
||||
<div class="avatars-container">
|
||||
{#each persons as person}
|
||||
<div class="combine-avatar {size}">
|
||||
<Avatar avatar={person.avatar} {size} />
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.avatars-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.combine-avatar.inline:not(:first-child) { margin-left: calc(1px - (.875rem / 2)); }
|
||||
.combine-avatar.x-small:not(:first-child) { margin-left: calc(1px - (1.5rem / 2)); }
|
||||
.combine-avatar.small:not(:first-child) { margin-left: calc(1px - 1rem); }
|
||||
.combine-avatar.medium:not(:first-child) { margin-left: calc(1px - (2.25rem / 2)); }
|
||||
.combine-avatar.large:not(:first-child) { margin-left: calc(1px - (4.5rem / 2)); }
|
||||
.combine-avatar.x-large:not(:first-child) { margin-left: calc(1px - (7.5rem / 2)); }
|
||||
.combine-avatar:not(:last-child) { mask: radial-gradient(circle at 100% 50%, rgba(0, 0, 0, 0) 48.5%, rgb(0, 0, 0) 50%); }
|
||||
}
|
||||
</style>
|
@ -13,7 +13,6 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte'
|
||||
import type { IntlString } from '@anticrm/platform'
|
||||
import { getClient } from '../utils'
|
||||
|
||||
|
@ -36,7 +36,7 @@
|
||||
|
||||
<div class="selectPopup">
|
||||
<div class="header">
|
||||
<input type='text' bind:value={search} placeholder={phTraslate} on:input={(ev) => { }} on:change/>
|
||||
<input type='text' bind:value={search} placeholder={phTraslate} on:input={() => { }} on:change/>
|
||||
</div>
|
||||
<div class="scroll">
|
||||
<div class="box">
|
||||
|
@ -18,7 +18,7 @@
|
||||
import contact, { Contact, formatName } from '@anticrm/contact'
|
||||
import type { Class, Ref } from '@anticrm/core'
|
||||
import type { IntlString } from '@anticrm/platform'
|
||||
import type { TooltipAlignment } from '@anticrm/ui'
|
||||
import type { TooltipAlignment, ButtonKind, ButtonSize } from '@anticrm/ui'
|
||||
import { Button, Label, showPopup, Tooltip } from '@anticrm/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import presentation from '..'
|
||||
@ -35,8 +35,8 @@
|
||||
export let allowDeselect = false
|
||||
export let titleDeselect: IntlString | undefined = undefined
|
||||
export let readonly = false
|
||||
export let kind: 'primary' | 'secondary' | 'no-border' | 'transparent' | 'link' | 'dangerous' = 'no-border'
|
||||
export let size: 'small' | 'medium' | 'large' | 'x-large' = 'small'
|
||||
export let kind: ButtonKind = 'no-border'
|
||||
export let size: ButtonSize = 'small'
|
||||
export let justify: 'left' | 'center' = 'center'
|
||||
export let width: string | undefined = undefined
|
||||
export let labelDirection: TooltipAlignment | undefined = undefined
|
||||
@ -45,7 +45,6 @@
|
||||
|
||||
let selected: Contact | undefined
|
||||
let container: HTMLElement
|
||||
let opened: boolean = false
|
||||
|
||||
const client = getClient()
|
||||
|
||||
@ -62,14 +61,13 @@
|
||||
</script>
|
||||
|
||||
<div bind:this={container} class="min-w-0">
|
||||
<Tooltip label={label} fill={width === '100%'} direction={labelDirection}>
|
||||
<Tooltip {label} fill={width === '100%'} direction={labelDirection}>
|
||||
<Button
|
||||
icon={(size === 'x-large' && selected) ? undefined : IconPerson}
|
||||
width={width ?? 'min-content'}
|
||||
{size} {kind} {justify}
|
||||
on:click={() => {
|
||||
if (!opened && !readonly) {
|
||||
opened = true
|
||||
if (!readonly) {
|
||||
showPopup(UsersPopup, { _class, allowDeselect, selected: value, titleDeselect, placeholder }, container, (result) => {
|
||||
if (result === null) {
|
||||
value = null
|
||||
@ -79,7 +77,6 @@
|
||||
value = result._id
|
||||
dispatch('change', value)
|
||||
}
|
||||
opened = false
|
||||
})
|
||||
}
|
||||
}}
|
||||
|
@ -15,18 +15,26 @@
|
||||
<script lang="ts">
|
||||
import { Person } from '@anticrm/contact'
|
||||
import type { Class, Doc, Ref } from '@anticrm/core'
|
||||
import { IntlString } from '@anticrm/platform'
|
||||
import { ActionIcon, CircleButton, IconAdd, IconClose, Label, ShowMore, showPopup } from '@anticrm/ui'
|
||||
import type { IntlString } from '@anticrm/platform'
|
||||
import { translate } from '@anticrm/platform'
|
||||
import type { ButtonKind, ButtonSize, TooltipAlignment } from '@anticrm/ui'
|
||||
import { Tooltip, showPopup, Button } from '@anticrm/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { UserInfo } from '..'
|
||||
import presentation, { CombineAvatars, UsersPopup } from '..'
|
||||
import { createQuery } from '../utils'
|
||||
import UsersPopup from './UsersPopup.svelte'
|
||||
import Members from './icons/Members.svelte'
|
||||
|
||||
export let items: Ref<Person>[] = []
|
||||
export let _class: Ref<Class<Doc>>
|
||||
export let title: IntlString
|
||||
export let label: IntlString
|
||||
export let noItems: IntlString
|
||||
|
||||
export let kind: ButtonKind = 'no-border'
|
||||
export let size: ButtonSize = 'small'
|
||||
export let justify: 'left' | 'center' = 'center'
|
||||
export let width: string | undefined = undefined
|
||||
export let labelDirection: TooltipAlignment | undefined = undefined
|
||||
|
||||
let persons: Person[] = []
|
||||
|
||||
const query = createQuery()
|
||||
@ -37,71 +45,45 @@
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
async function addRef (person: Person): Promise<void> {
|
||||
dispatch('open', person)
|
||||
}
|
||||
async function addPerson (evt: Event): Promise<void> {
|
||||
showPopup(
|
||||
UsersPopup,
|
||||
{
|
||||
_class,
|
||||
title,
|
||||
label,
|
||||
multiSelect: true,
|
||||
allowDeselect: false,
|
||||
ignoreUsers: items
|
||||
selectedUsers: items
|
||||
},
|
||||
evt.target as HTMLElement,
|
||||
() => { },
|
||||
(result) => {
|
||||
// We have some value selected
|
||||
if (result !== undefined) {
|
||||
addRef(result)
|
||||
items = result
|
||||
dispatch('update', items)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
async function removePerson (person: Person): Promise<void> {
|
||||
dispatch('delete', person)
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="flex-row">
|
||||
<ShowMore>
|
||||
<div class="persons-container">
|
||||
<div class="flex flex-reverse">
|
||||
<div class="ml-4">
|
||||
<CircleButton icon={IconAdd} size={'small'} selected on:click={addPerson} />
|
||||
<Tooltip {label} fill={width === '100%'} direction={labelDirection}>
|
||||
<Button
|
||||
icon={persons.length === 0 ? Members : undefined}
|
||||
label={persons.length === 0 ? presentation.string.Members : undefined}
|
||||
width={width ?? 'min-content'}
|
||||
{kind} {size} {justify}
|
||||
on:click={addPerson}
|
||||
>
|
||||
<svelte:fragment slot="content">
|
||||
{#if persons.length > 0}
|
||||
<div class="flex-row-center flex-nowrap">
|
||||
<CombineAvatars {_class} bind:items size={'inline'} />
|
||||
{#await translate(presentation.string.NumberMembers, { lenght: persons.length }) then text}
|
||||
<span class="ml-1-5">{text}</span>
|
||||
{/await}
|
||||
</div>
|
||||
<div class="person-items">
|
||||
{#if items?.length === 0}
|
||||
<div class="flex flex-grow title-center">
|
||||
<Label label={noItems} />
|
||||
</div>
|
||||
{/if}
|
||||
{#each persons as person}
|
||||
<div class="antiComponentBox flex-center antiComponentBoxFocused">
|
||||
<UserInfo value={person} size={'x-small'} />
|
||||
<div class="ml-1">
|
||||
<ActionIcon icon={IconClose} size={'small'} action={() => removePerson(person)} />
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ShowMore>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.persons-container {
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
.person-items {
|
||||
flex-grow: 1;
|
||||
display: grid;
|
||||
gap: 0.25rem;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
.margin_025 {
|
||||
margin: 0.25rem;
|
||||
}
|
||||
</style>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</Button>
|
||||
</Tooltip>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<script lang="ts">
|
||||
import type { IntlString } from '@anticrm/platform'
|
||||
import { translate } from '@anticrm/platform'
|
||||
import { afterUpdate, createEventDispatcher } from 'svelte'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
|
||||
import { Tooltip, CheckBox } from '@anticrm/ui'
|
||||
import UserInfo from './UserInfo.svelte'
|
||||
@ -28,10 +28,11 @@
|
||||
export let _class: Ref<Class<Person>>
|
||||
export let selected: Ref<Person> | undefined
|
||||
|
||||
export let multiSelect: boolean = false
|
||||
export let allowDeselect: boolean = false
|
||||
export let titleDeselect: IntlString | undefined = undefined
|
||||
export let placeholder: IntlString = presentation.string.Search
|
||||
|
||||
export let selectedUsers: Ref<Person>[] = []
|
||||
export let ignoreUsers: Ref<Person>[] = []
|
||||
|
||||
let search: string = ''
|
||||
@ -43,23 +44,47 @@
|
||||
|
||||
let phTraslate: string = ''
|
||||
$: if (placeholder) translate(placeholder, {}).then(res => { phTraslate = res })
|
||||
afterUpdate(() => { dispatch('update', Date.now()) })
|
||||
|
||||
const isSelected = (person: Person): boolean => {
|
||||
if (selectedUsers.filter(p => p === person._id).length > 0) return true
|
||||
return false
|
||||
}
|
||||
const checkSelected = (person: Person): void => {
|
||||
if (isSelected(person)) selectedUsers = selectedUsers.filter(p => p !== person._id)
|
||||
else selectedUsers.push(person._id)
|
||||
objects = objects
|
||||
dispatch('update', selectedUsers)
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="selectPopup">
|
||||
<div class="header">
|
||||
<input type='text' bind:value={search} placeholder={phTraslate} on:input={(ev) => { }} on:change/>
|
||||
<input type='text' bind:value={search} placeholder={phTraslate} on:change/>
|
||||
</div>
|
||||
<div class="scroll">
|
||||
<div class="box">
|
||||
{#each objects as person}
|
||||
<button class="menu-item flex-between" on:click={() => { dispatch('close', person) }}>
|
||||
<button class="menu-item" on:click={() => {
|
||||
if (!multiSelect) {
|
||||
selected = person._id === selected ? undefined : person._id
|
||||
dispatch('close', selected != undefined ? person : undefined)
|
||||
} else checkSelected(person)
|
||||
}}>
|
||||
{#if multiSelect}
|
||||
<div class="check pointer-events-none">
|
||||
<CheckBox checked={isSelected(person)} primary />
|
||||
</div>
|
||||
{/if}
|
||||
<UserInfo size={'x-small'} value={person} />
|
||||
{#if allowDeselect && person._id === selected}
|
||||
<div class="check" on:click|stopPropagation={() => { dispatch('close', null) }}>
|
||||
<Tooltip label={titleDeselect ?? presentation.string.Deselect}>
|
||||
<CheckBox checked primary />
|
||||
</Tooltip>
|
||||
<div class="check-right pointer-events-none">
|
||||
{#if titleDeselect}
|
||||
<Tooltip label={titleDeselect ?? presentation.string.Deselect}>
|
||||
<CheckBox checked circle primary />
|
||||
</Tooltip>
|
||||
{:else}
|
||||
<CheckBox checked circle primary />
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</button>
|
||||
|
@ -15,7 +15,7 @@
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
export let size: 'x-small' | 'small' | 'medium' | 'large' | 'x-large'
|
||||
export let size: 'inline' | 'x-small' | 'small' | 'medium' | 'large' | 'x-large'
|
||||
|
||||
const fill: string = 'var(--theme-caption-color)'
|
||||
</script>
|
||||
@ -30,6 +30,10 @@
|
||||
.svg-avatar {
|
||||
.op { opacity: .05; }
|
||||
}
|
||||
.inline {
|
||||
width: .75rem;
|
||||
height: .75rem;
|
||||
}
|
||||
.x-small {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
|
29
packages/presentation/src/components/icons/Members.svelte
Normal file
29
packages/presentation/src/components/icons/Members.svelte
Normal file
@ -0,0 +1,29 @@
|
||||
<!--
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
// Copyright © 2021 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
export let size: 'small' | 'medium' | 'large'
|
||||
const fill: string = 'currentColor'
|
||||
</script>
|
||||
|
||||
<svg class="svg-{size}" {fill} viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10.2857 5.44444C10.2857 6.79447 9.26237 7.88889 8 7.88889C6.73764 7.88889 5.71429 6.79447 5.71429 5.44444C5.71429 4.09441 6.73764 3 8 3C9.26237 3 10.2857 4.09441 10.2857 5.44444Z" />
|
||||
<path d="M3.42857 11.9603C3.42857 10.9748 3.98128 10.081 4.85831 9.7786C5.79546 9.45545 7.02325 9.11111 8 9.11111C8.97675 9.11111 10.2045 9.45545 11.1417 9.77859C12.0187 10.081 12.5714 10.9748 12.5714 11.9603V12.7778C12.5714 13.4528 12.0598 14 11.4286 14H4.57143C3.94025 14 3.42857 13.4528 3.42857 12.7778V11.9603Z" />
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.63272 4.75066C4.59249 4.97531 4.57143 5.20725 4.57143 5.44444C4.57143 6.00206 4.68782 6.5306 4.89604 7.00381C4.59565 7.53433 4.05083 7.88889 3.42857 7.88889C2.4818 7.88889 1.71429 7.06808 1.71429 6.05556C1.71429 5.04303 2.4818 4.22222 3.42857 4.22222C3.89788 4.22222 4.32315 4.42391 4.63272 4.75066Z" />
|
||||
<path d="M2.28571 12.7778V11.9603C2.28571 10.8522 2.76028 9.77952 3.59669 9.11537C3.5397 9.11257 3.48361 9.11111 3.42857 9.11111C2.69601 9.11111 1.77516 9.36937 1.0723 9.61172C0.414531 9.83853 0 10.5089 0 11.248V11.8611C0 12.3674 0.383756 12.7778 0.857143 12.7778H2.28571Z" />
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.3716 4.75066C11.4118 4.97531 11.4329 5.20725 11.4329 5.44444C11.4329 6.00206 11.3166 6.5306 11.1086 7.00381C11.4087 7.53433 11.953 7.88889 12.5747 7.88889C13.5205 7.88889 14.2873 7.06808 14.2873 6.05556C14.2873 5.04303 13.5205 4.22222 12.5747 4.22222C12.1058 4.22222 11.6809 4.42391 11.3716 4.75066Z" />
|
||||
<path d="M13.7164 12.7778V11.9603C13.7164 10.8522 13.2423 9.77952 12.4067 9.11537C12.4636 9.11257 12.5197 9.11111 12.5747 9.11111C13.3065 9.11111 14.2265 9.36937 14.9287 9.61172C15.5859 9.83853 16 10.5089 16 11.248V11.8611C16 12.3674 15.6166 12.7778 15.1437 12.7778H13.7164Z" />
|
||||
</svg>
|
@ -21,6 +21,7 @@ export { default as AttributeBarEditor } from './components/AttributeBarEditor.s
|
||||
export { default as AttributeEditor } from './components/AttributeEditor.svelte'
|
||||
export { default as AttributesBar } from './components/AttributesBar.svelte'
|
||||
export { default as Avatar } from './components/Avatar.svelte'
|
||||
export { default as CombineAvatars } from './components/CombineAvatars.svelte'
|
||||
export { default as Card } from './components/Card.svelte'
|
||||
export { default as EditableAvatar } from './components/EditableAvatar.svelte'
|
||||
export { default as Members } from './components/Members.svelte'
|
||||
|
@ -43,7 +43,8 @@ export default plugin(presentationId, {
|
||||
Members: '' as IntlString,
|
||||
Search: '' as IntlString,
|
||||
Unassigned: '' as IntlString,
|
||||
CreateMore: '' as IntlString
|
||||
CreateMore: '' as IntlString,
|
||||
NumberMembers: '' as IntlString
|
||||
},
|
||||
metadata: {
|
||||
RequiredVersion: '' as Metadata<string>
|
||||
|
@ -79,6 +79,7 @@
|
||||
--popup-shadow: rgb(0 0 0 / 20%) 0px 4px 24px;
|
||||
--card-shadow: rgb(0 0 0 / 50%) 0px 16px 70px;
|
||||
--card-overlay-color: rgba(28, 29, 31, .5);
|
||||
--avatar-bg-color: #4f5358;
|
||||
|
||||
--button-bg-color: #303236;
|
||||
--button-bg-hover: #37383b;
|
||||
|
@ -185,7 +185,7 @@ p:last-child { margin-block-end: 0; }
|
||||
|
||||
&.circle {
|
||||
padding: .25rem;
|
||||
background-color: var(--popup-bg-hover);
|
||||
background-color: var(--avatar-bg-color);
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
@ -286,6 +286,7 @@ p:last-child { margin-block-end: 0; }
|
||||
.step-tb75 + .step-tb75 { margin-top: .75rem; }
|
||||
|
||||
.ml-1 { margin-left: .25rem; }
|
||||
.ml-1-5 { margin-left: .375rem; }
|
||||
.ml-2 { margin-left: .5rem; }
|
||||
.ml-3 { margin-left: .75rem; }
|
||||
.ml-4 { margin-left: 1rem; }
|
||||
@ -378,6 +379,7 @@ p:last-child { margin-block-end: 0; }
|
||||
.h-full { height: 100%; }
|
||||
.h-2 { height: .5rem; }
|
||||
.h-9 { height: 2.25rem; }
|
||||
.h-16 { height: 4rem; }
|
||||
.h-18 { height: 4.5rem; }
|
||||
.w-full { width: 100%; }
|
||||
.w-9 { width: 2.25rem; }
|
||||
|
@ -65,6 +65,7 @@
|
||||
color: var(--caption-color);
|
||||
cursor: pointer;
|
||||
|
||||
&.high { height: 3rem; }
|
||||
.icon {
|
||||
margin-right: .75rem;
|
||||
width: 1rem;
|
||||
@ -84,14 +85,13 @@
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
.check {
|
||||
.check, .check-right {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
margin-left: 1rem;
|
||||
width: 1rem;
|
||||
margin-right: .75rem;
|
||||
height: 2rem;
|
||||
}
|
||||
.check-right { margin: 0 0 0 2rem; }
|
||||
&:hover { background-color: var(--popup-bg-hover); }
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import type { IntlString, Asset } from '@anticrm/platform'
|
||||
import type { AnySvelteComponent } from '../types'
|
||||
import type { AnySvelteComponent, ButtonKind, ButtonSize } from '../types'
|
||||
import Spinner from './Spinner.svelte'
|
||||
import Label from './Label.svelte'
|
||||
import Icon from './Icon.svelte'
|
||||
@ -22,8 +22,8 @@
|
||||
|
||||
export let label: IntlString | undefined = undefined
|
||||
export let labelParams: Record<string, any> = {}
|
||||
export let kind: 'primary' | 'secondary' | 'no-border' | 'transparent' | 'link' | 'link-bordered' | 'dangerous' = 'secondary'
|
||||
export let size: 'small' | 'medium' | 'large' | 'x-large' = 'medium'
|
||||
export let kind: ButtonKind = 'secondary'
|
||||
export let size: ButtonSize = 'medium'
|
||||
export let shape: 'circle' | undefined = undefined
|
||||
export let icon: Asset | AnySvelteComponent | undefined = undefined
|
||||
export let justify: 'left' | 'center' = 'center'
|
||||
@ -83,7 +83,8 @@
|
||||
<style lang="scss">
|
||||
.small {
|
||||
height: 1.5rem;
|
||||
line-height: 1.5rem;
|
||||
font-size: .75rem;
|
||||
line-height: .75rem;
|
||||
&.only-icon { width: 1.5rem; }
|
||||
}
|
||||
.medium {
|
||||
|
@ -34,13 +34,6 @@
|
||||
<label class="checkbox" class:circle class:primary class:checked>
|
||||
<input class="chBox" type="checkbox" bind:checked on:change={handleValueChanged} />
|
||||
<svg class="checkSVG" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
{#if !circle}
|
||||
<path
|
||||
class="back"
|
||||
class:primary
|
||||
d="M4,0h8c2.2,0,4,1.8,4,4v8c0,2.2-1.8,4-4,4H4c-2.2,0-4-1.8-4-4V4C0,1.8,1.8,0,4,0z"
|
||||
/>
|
||||
{/if}
|
||||
{#if checked}
|
||||
{#if symbol === 'minus'}
|
||||
<rect class="check" class:primary x="4" y="7.4" width="8" height="1.2" />
|
||||
@ -54,12 +47,27 @@
|
||||
<style lang="scss">
|
||||
.checkbox {
|
||||
flex-shrink: 0;
|
||||
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
width: .875rem;
|
||||
height: .875rem;
|
||||
border: 1px solid var(--dark-color);
|
||||
border-radius: .25rem;
|
||||
|
||||
&.circle {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
border-radius: 50%;
|
||||
}
|
||||
&.checked {
|
||||
background-color: var(--accent-color);
|
||||
border-color: transparent;
|
||||
}
|
||||
&.primary.checked {
|
||||
background-color: var(--primary-bg-color);
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.chBox {
|
||||
position: absolute;
|
||||
@ -94,35 +102,13 @@
|
||||
}
|
||||
}
|
||||
.checkSVG {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
border-radius: 0.25rem;
|
||||
width: .875rem;
|
||||
height: .875rem;
|
||||
|
||||
.back {
|
||||
fill: var(--theme-button-bg-hovered);
|
||||
}
|
||||
.check {
|
||||
visibility: hidden;
|
||||
fill: var(--theme-button-bg-enabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.circle {
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
background-color: var(--theme-button-bg-hovered);
|
||||
border: 1px solid var(--theme-bg-focused-color);
|
||||
border-radius: 50%;
|
||||
|
||||
&.checked {
|
||||
background-color: var(--theme-bg-check);
|
||||
}
|
||||
&.primary {
|
||||
border-color: transparent;
|
||||
&.checked {
|
||||
background-color: var(--primary-button-enabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -20,7 +20,7 @@
|
||||
import Label from './Label.svelte'
|
||||
import Icon from './Icon.svelte'
|
||||
import { showPopup, Button, Tooltip, DropdownPopup } from '..'
|
||||
import type { AnySvelteComponent, ListItem, TooltipAlignment } from '../types'
|
||||
import type { AnySvelteComponent, ListItem, TooltipAlignment, ButtonKind, ButtonSize } from '../types'
|
||||
|
||||
export let icon: Asset | AnySvelteComponent | undefined = undefined
|
||||
export let label: IntlString
|
||||
@ -28,8 +28,8 @@
|
||||
export let items: ListItem[] = []
|
||||
export let selected: ListItem | undefined = undefined
|
||||
|
||||
export let kind: 'primary' | 'secondary' | 'no-border' | 'transparent' | 'link' | 'dangerous' = 'no-border'
|
||||
export let size: 'small' | 'medium' | 'large' | 'x-large' = 'small'
|
||||
export let kind: ButtonKind = 'no-border'
|
||||
export let size: ButtonSize = 'small'
|
||||
export let justify: 'left' | 'center' = 'center'
|
||||
export let width: string | undefined = undefined
|
||||
export let labelDirection: TooltipAlignment | undefined = undefined
|
||||
|
@ -16,7 +16,7 @@
|
||||
<script lang="ts">
|
||||
import { IntlString, Asset } from '@anticrm/platform'
|
||||
import DropdownLabelsPopup from './DropdownLabelsPopup.svelte'
|
||||
import type { AnySvelteComponent, DropdownTextItem, TooltipAlignment } from '../types'
|
||||
import type { AnySvelteComponent, DropdownTextItem, TooltipAlignment, ButtonKind, ButtonSize } from '../types'
|
||||
import { showPopup, Tooltip, Button, Label } from '..'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import ui from '../plugin'
|
||||
@ -27,8 +27,8 @@
|
||||
export let items: DropdownTextItem[]
|
||||
export let selected: DropdownTextItem['id'] | undefined = undefined
|
||||
|
||||
export let kind: 'primary' | 'secondary' | 'no-border' | 'transparent' | 'link' | 'dangerous' = 'no-border'
|
||||
export let size: 'small' | 'medium' | 'large' | 'x-large' = 'small'
|
||||
export let kind: ButtonKind = 'no-border'
|
||||
export let size: ButtonSize = 'small'
|
||||
export let justify: 'left' | 'center' = 'center'
|
||||
export let width: string | undefined = undefined
|
||||
export let labelDirection: TooltipAlignment | undefined = undefined
|
||||
@ -73,46 +73,3 @@
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
<!-- <div class="flex-col cursor-pointer"
|
||||
bind:this={btn}
|
||||
on:click|preventDefault={() => {
|
||||
if (!opened) {
|
||||
opened = true
|
||||
showPopup(DropdownLabelsPopup, { placeholder, items, selected }, btn, (result) => {
|
||||
if (result) {
|
||||
selected = result
|
||||
dispatch('selected', result)
|
||||
}
|
||||
opened = false
|
||||
})
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div class="overflow-label label"><Label label={label} /></div>
|
||||
<div class="flex-row-center space">
|
||||
<span class="mr-1">
|
||||
{#if opened}
|
||||
<IconUp size={'small'} />
|
||||
{:else}
|
||||
<IconDown size={'small'} />
|
||||
{/if}
|
||||
</span>
|
||||
<span class="overflow-label" class:caption-color={selected} class:content-dark-color={!selected}>
|
||||
{#if selectedItem}
|
||||
{selectedItem.label}
|
||||
{:else}
|
||||
<Label label={none} />
|
||||
{/if}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.label {
|
||||
margin-bottom: .125rem;
|
||||
font-weight: 500;
|
||||
font-size: .75rem;
|
||||
color: var(--theme-content-accent-color);
|
||||
}
|
||||
</style> -->
|
||||
|
@ -20,7 +20,7 @@ import { readable } from 'svelte/store'
|
||||
|
||||
import Root from './components/internal/Root.svelte'
|
||||
|
||||
export type { AnyComponent, AnySvelteComponent, Action, LabelAndProps, TooltipAlignment, AnySvelteComponentWithProps, Location, PopupAlignment } from './types'
|
||||
export type { AnyComponent, AnySvelteComponent, Action, LabelAndProps, TooltipAlignment, AnySvelteComponentWithProps, Location, PopupAlignment, ButtonKind, ButtonSize } from './types'
|
||||
// export { applicationShortcutKey } from './utils'
|
||||
export { getCurrentLocation, locationToUrl, navigate, location } from './location'
|
||||
|
||||
|
@ -123,9 +123,9 @@ export function fitPopupElement (modalHTML: HTMLElement, element?: PopupAlignmen
|
||||
const rectPopup = modalHTML.getBoundingClientRect()
|
||||
// Vertical
|
||||
if (rect.bottom + rectPopup.height + 28 <= document.body.clientHeight) {
|
||||
modalHTML.style.top = `calc(${rect.bottom}px + .75rem)`
|
||||
modalHTML.style.top = `calc(${rect.bottom}px + .125rem)`
|
||||
} else if (rectPopup.height + 28 < rect.top) {
|
||||
modalHTML.style.bottom = `calc(${document.body.clientHeight - rect.y}px + .75rem)`
|
||||
modalHTML.style.bottom = `calc(${document.body.clientHeight - rect.y}px + .125rem)`
|
||||
} else {
|
||||
modalHTML.style.top = modalHTML.style.bottom = '1rem'
|
||||
}
|
||||
|
@ -63,8 +63,9 @@ export interface Tab {
|
||||
|
||||
export type TabModel = Tab[]
|
||||
|
||||
export type ButtonKind = 'primary' | 'secondary' | 'no-border' | 'transparent' | 'link' | 'link-bordered' | 'dangerous'
|
||||
export type ButtonSize = 'small' | 'medium' | 'large' | 'x-large'
|
||||
export type PopupAlignment = HTMLElement | EventTarget | null | 'right' | 'top' | 'account' | 'full' | 'content' | 'middle'
|
||||
|
||||
export type TooltipAlignment = 'top' | 'bottom' | 'left' | 'right'
|
||||
|
||||
export interface LabelAndProps {
|
||||
|
@ -72,7 +72,7 @@
|
||||
<UserBoxList
|
||||
_class={contact.class.Employee}
|
||||
items={participants}
|
||||
title={calendar.string.Participants}
|
||||
label={calendar.string.Participants}
|
||||
on:open={(evt) => {
|
||||
participants.push(evt.detail._id)
|
||||
participants = participants
|
||||
|
@ -61,7 +61,7 @@
|
||||
<UserBoxList
|
||||
_class={contact.class.Employee}
|
||||
items={object.participants}
|
||||
title={calendar.string.Participants}
|
||||
label={calendar.string.Participants}
|
||||
on:open={(evt) => {
|
||||
client.update(object, { $push: { participants: evt.detail._id } })
|
||||
}}
|
||||
|
@ -78,7 +78,7 @@
|
||||
<UserBoxList
|
||||
_class={contact.class.Employee}
|
||||
items={participants}
|
||||
title={calendar.string.Participants}
|
||||
label={calendar.string.Participants}
|
||||
on:open={(evt) => {
|
||||
participants.push(evt.detail._id)
|
||||
participants = participants
|
||||
|
@ -19,7 +19,7 @@
|
||||
import { IntlString } from '@anticrm/platform'
|
||||
import { createQuery } from '@anticrm/presentation'
|
||||
import { Dropdown } from '@anticrm/ui'
|
||||
import type { TooltipAlignment } from '@anticrm/ui'
|
||||
import type { TooltipAlignment, ButtonKind, ButtonSize } from '@anticrm/ui'
|
||||
import { ListItem } from '@anticrm/ui/src/types'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import contact from '../plugin'
|
||||
@ -28,8 +28,8 @@
|
||||
export let value: Ref<Organization> | undefined
|
||||
export let label: IntlString = contact.string.Organization
|
||||
|
||||
export let kind: 'primary' | 'secondary' | 'no-border' | 'transparent' | 'link' | 'dangerous' = 'no-border'
|
||||
export let size: 'small' | 'medium' | 'large' | 'x-large' = 'small'
|
||||
export let kind: ButtonKind = 'no-border'
|
||||
export let size: ButtonSize = 'small'
|
||||
export let justify: 'left' | 'center' = 'center'
|
||||
export let width: string | undefined = undefined
|
||||
export let labelDirection: TooltipAlignment | undefined = undefined
|
||||
|
@ -165,18 +165,6 @@
|
||||
placeholder={recruit.string.Location} bind:value={location}
|
||||
maxWidth={'37.5rem'} kind={'small-style'}
|
||||
/>
|
||||
<UserBoxList
|
||||
_class={contact.class.Employee}
|
||||
items={doc.participants}
|
||||
title={calendar.string.Participants}
|
||||
on:open={(evt) => {
|
||||
doc.participants = [...(doc.participants ?? []), evt.detail._id]
|
||||
}}
|
||||
on:delete={(evt) => {
|
||||
doc.participants = doc.participants?.filter((it) => it !== evt.detail._id) ?? [currentUser.employee]
|
||||
}}
|
||||
noItems={calendar.string.NoParticipants}
|
||||
/>
|
||||
<StyledTextBox
|
||||
emphasized
|
||||
showButtons={false}
|
||||
@ -199,5 +187,14 @@
|
||||
/>
|
||||
<DateRangePresenter bind:value={startDate} labelNull={recruit.string.StartDate} withTime editable on:change={updateStart} />
|
||||
<DateRangePresenter bind:value={dueDate} labelNull={recruit.string.DueDate} withTime editable />
|
||||
<UserBoxList
|
||||
_class={contact.class.Employee}
|
||||
items={doc.participants}
|
||||
label={calendar.string.Participants}
|
||||
on:update={(evt) => {
|
||||
doc.participants = evt.detail
|
||||
}}
|
||||
noItems={calendar.string.NoParticipants}
|
||||
/>
|
||||
</svelte:fragment>
|
||||
</Card>
|
||||
|
@ -86,7 +86,7 @@
|
||||
<UserBoxList
|
||||
_class={contact.class.Employee}
|
||||
items={object.participants}
|
||||
title={calendar.string.Participants}
|
||||
label={calendar.string.Participants}
|
||||
on:open={(evt) => {
|
||||
client.update(object, { $push: { participants: evt.detail._id } })
|
||||
}}
|
||||
|
@ -69,11 +69,10 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="antiPopup">
|
||||
<div class="ap-space" />
|
||||
<div class="ap-scroll"><div class="ap-box">
|
||||
<div class="selectPopup">
|
||||
<div class="scroll"><div class="box">
|
||||
{#await getItems() then items}
|
||||
<div class="ap-menuItem flex-row-center" on:click={() => { editProfile(items) }}>
|
||||
<div class="menu-item high flex-row-center" on:click={() => { editProfile(items) }}>
|
||||
{#if employee}
|
||||
<Avatar avatar={employee.avatar} size={'medium'} />
|
||||
{/if}
|
||||
@ -86,7 +85,7 @@
|
||||
</div>
|
||||
{#if items}
|
||||
{#each filterItems(items) as item }
|
||||
<button class="ap-menuItem" on:click={() => selectCategory(item)}>
|
||||
<button class="menu-item" on:click={() => selectCategory(item)}>
|
||||
<div class='mr-2'>
|
||||
<Icon icon={item.icon} size={'small'}/>
|
||||
</div>
|
||||
@ -94,13 +93,13 @@
|
||||
</button>
|
||||
{/each}
|
||||
{/if}
|
||||
<button class="ap-menuItem" on:click={selectWorkspace}>
|
||||
<button class="menu-item" on:click={selectWorkspace}>
|
||||
<div class='mr-2'>
|
||||
<Icon icon={setting.icon.SelectWorkspace} size={'small'}/>
|
||||
</div>
|
||||
<Label label={setting.string.SelectWorkspace} />
|
||||
</button>
|
||||
<button class="ap-menuItem" on:click={signOut}>
|
||||
<button class="menu-item" on:click={signOut}>
|
||||
<div class='mr-2'>
|
||||
<Icon icon={setting.icon.Signout} size={'small'}/>
|
||||
</div>
|
||||
@ -108,5 +107,4 @@
|
||||
</button>
|
||||
{/await}
|
||||
</div></div>
|
||||
<div class="ap-space" />
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user