Fixed the filling of the status icon. Fixed jumping popups. (#2232)

Signed-off-by: Alexander Platov <sas_lord@mail.ru>
This commit is contained in:
Alexander Platov 2022-07-10 17:22:13 +03:00 committed by GitHub
parent bba0227a4f
commit 12da24f18c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 125 additions and 74 deletions

View File

@ -194,6 +194,7 @@
.antiPopup {
display: flex;
flex-direction: column;
width: auto;
min-height: 0;
min-width: 0;
max-width: 30rem;

View File

@ -13,7 +13,7 @@
// limitations under the License.
-->
<script lang="ts">
import { createEventDispatcher } from 'svelte'
import { afterUpdate, createEventDispatcher } from 'svelte'
export let selection: number = 0
export let count: number
@ -53,6 +53,8 @@
r?.scrollIntoView({ behavior: 'auto', block: 'nearest' })
}
}
afterUpdate(() => dispatch('changeContent', true))
</script>
{#if count}

View File

@ -21,6 +21,7 @@
import Icon from './Icon.svelte'
import Label from './Label.svelte'
import MouseSpeedTracker from './MouseSpeedTracker.svelte'
import { resizeObserver } from '../resize'
export let actions: Action[] = []
export let ctx: any = undefined
@ -66,7 +67,7 @@
}
afterUpdate(() => {
dispatch('update', Date.now())
dispatch('changeContent', true)
})
onMount(() => {
if (btns[0]) {
@ -110,7 +111,13 @@
$: popup?.focus()
</script>
<div class="antiPopup" on:keydown={keyDown}>
<div
class="antiPopup"
use:resizeObserver={() => {
dispatch('changeContent', true)
}}
on:keydown={keyDown}
>
<MouseSpeedTracker bind:focusSpeed />
<div class="ap-space" />
<slot name="header" />

View File

@ -124,7 +124,9 @@
on:fullsize={() => {
fullSize = !fullSize
}}
on:changeContent={fitPopup}
on:changeContent={() => {
fitPopup()
}}
/>
</div>

View File

@ -14,7 +14,7 @@
-->
<script lang="ts">
import type { Asset, IntlString } from '@anticrm/platform'
import { createEventDispatcher } from 'svelte'
import { afterUpdate, createEventDispatcher } from 'svelte'
import { createFocusManager } from '../focus'
import EditBox from './EditBox.svelte'
import FocusHandler from './FocusHandler.svelte'
@ -22,6 +22,8 @@
import IconCheck from './icons/Check.svelte'
import Label from './Label.svelte'
import ListView from './ListView.svelte'
import type { AnySvelteComponent } from '../types'
import { resizeObserver } from '../resize'
interface ValueType {
id: number | string
@ -30,6 +32,9 @@
label?: IntlString
text?: string
isSelected?: boolean
component?: AnySvelteComponent
props?: Record<string, any>
}
export let placeholder: IntlString | undefined = undefined
@ -75,6 +80,8 @@
$: filteredObjects = value.filter((el) => (el.label ?? el.text ?? '').toLowerCase().includes(search.toLowerCase()))
$: huge = size === 'medium' || size === 'large'
afterUpdate(() => dispatch('changeContent', true))
</script>
<FocusHandler {manager} />
@ -83,6 +90,9 @@
class="selectPopup"
class:full-width={width === 'full'}
class:max-width-40={width === 'large'}
use:resizeObserver={() => {
dispatch('changeContent', true)
}}
on:keydown={onKeydown}
>
{#if searchable}
@ -100,7 +110,12 @@
{/if}
<div class="scroll">
<div class="box">
<ListView bind:this={list} count={filteredObjects.length} bind:selection>
<ListView
bind:this={list}
count={filteredObjects.length}
bind:selection
on:changeContent={() => dispatch('changeContent', true)}
>
<svelte:fragment slot="item" let:item={itemId}>
{@const item = filteredObjects[itemId]}
<button
@ -117,18 +132,22 @@
{/if}
</div>
{/if}
{#if item.icon}
<div class="mr-2">
<Icon icon={item.icon} fill={item.iconColor} {size} />
</div>
{/if}
<span class="label" class:text-base={huge}>
{#if item.label}
<Label label={item.label} />
{:else if item.text}
<span>{item.text}</span>
{#if item.component}
<svelte:component this={item.component} {...item.props} />
{:else}
{#if item.icon}
<div class="mr-2">
<Icon icon={item.icon} fill={item.iconColor} {size} />
</div>
{/if}
</span>
<span class="label" class:text-base={huge}>
{#if item.label}
<Label label={item.label} />
{:else if item.text}
<span>{item.text}</span>
{/if}
</span>
{/if}
</div>
</button>
</svelte:fragment>

View File

@ -1,11 +1,12 @@
<script lang="ts">
import { Asset } from '@anticrm/platform'
import { afterUpdate, createEventDispatcher } from 'svelte'
import { getClient } from '@anticrm/presentation'
import { Menu, Action, showPopup, closePopup } from '@anticrm/ui'
import view from '@anticrm/view'
import contact from '../plugin'
const dispatch = createEventDispatcher()
const client = getClient()
const actions: Action[] = []
@ -28,6 +29,10 @@
})
}
})
afterUpdate(() => {
dispatch('changeContent', true)
})
</script>
<Menu {actions} />
<Menu {actions} on:changeContent={() => dispatch('changeContent', true)} />

View File

@ -1,45 +1,53 @@
<script lang="ts">
export let size: 'inline' | 'x-small' | 'small' | 'medium' | 'large' | 'full'
export let fill: string = 'currentColor'
export let status: 'backlog' | 'unstarted' | 'started' | 'completed' | 'canceled'
export let part: number = 1
export let count: number = 2
import { IconSize } from '@anticrm/ui'
import { IssueStatusCategory } from '@anticrm/tracker'
import tracker from '../../plugin'
$: d = count / part < count / 2 ? 1 : 0
export let size: IconSize
export let fill: string = 'currentColor'
export let category: IssueStatusCategory
export let statusIcon: {
index: number | undefined
count: number | undefined
} = { index: 0, count: 0 }
</script>
<svg
class="svg-{size}"
{fill}
style:transform={status === 'started' ? 'rotate(-90deg)' : ''}
style:transform={category._id === tracker.issueStatusCategory.Started ? 'rotate(-90deg)' : ''}
viewBox="0 0 14 14"
xmlns="http://www.w3.org/2000/svg"
>
{#if status === 'backlog'}
{#if category._id === tracker.issueStatusCategory.Backlog}
<path
d="M13.9,7.9l-2-0.3c0-0.2,0-0.4,0-0.7s0-0.4,0-0.7l2-0.3C14,6.4,14,6.7,14,7S14,7.6,13.9,7.9z M13.5,4.3c-0.2-0.6-0.5-1.1-0.9-1.6L11,4c0.3,0.3,0.5,0.7,0.7,1.1L13.5,4.3z M11.3,1.4L10,3C9.7,2.8,9.3,2.5,8.9,2.4l0.8-1.8C10.2,0.8,10.8,1.1,11.3,1.4z M7.9,0.1L7.7,2C7.4,2,7.2,2,7,2S6.6,2,6.3,2l-0.3-2C6.4,0,6.7,0,7,0S7.6,0,7.9,0.1z M4.3,0.5l0.8,1.8C4.7,2.5,4.3,2.8,4,3L2.7,1.4C3.2,1.1,3.8,0.8,4.3,0.5z M1.4,2.7L3,4C2.8,4.3,2.5,4.7,2.4,5.1L0.5,4.3C0.8,3.8,1.1,3.2,1.4,2.7z M0.1,6.1C0,6.4,0,6.7,0,7s0,0.6,0.1,0.9l2-0.3C2,7.4,2,7.2,2,7s0-0.4,0-0.7L0.1,6.1z M0.5,9.7l1.8-0.8C2.5,9.3,2.8,9.7,3,10l-1.6,1.2C1.1,10.8,0.8,10.2,0.5,9.7z M2.7,12.6L4,11c0.3,0.3,0.7,0.5,1.1,0.7l-0.8,1.8C3.8,13.2,3.2,12.9,2.7,12.6z M6.1,13.9l0.3-2c0.2,0,0.4,0,0.7,0s0.4,0,0.7,0l0.3,2C7.6,14,7.3,14,7,14S6.4,14,6.1,13.9z M9.7,13.5l-0.8-1.8c0.4-0.2,0.8-0.4,1.1-0.7l1.2,1.6C10.8,12.9,10.2,13.2,9.7,13.5z M12.6,11.3L11,10c0.3-0.3,0.5-0.7,0.7-1.1l1.8,0.8C13.2,10.2,12.9,10.8,12.6,11.3z"
/>
{:else if status === 'unstarted'}
{:else if category._id === tracker.issueStatusCategory.Unstarted}
<path
d="M7,0C3.1,0,0,3.1,0,7c0,3.9,3.1,7,7,7c3.9,0,7-3.1,7-7C14,3.1,10.9,0,7,0z M7,12c-2.8,0-5-2.2-5-5s2.2-5,5-5s5,2.2,5,5S9.8,12,7,12z"
/>
{:else if status === 'started'}
{:else if category._id === tracker.issueStatusCategory.Started}
<path
d="M7,0C3.1,0,0,3.1,0,7c0,3.9,3.1,7,7,7c3.9,0,7-3.1,7-7C14,3.1,10.9,0,7,0z M7,12c-2.8,0-5-2.2-5-5s2.2-5,5-5s5,2.2,5,5S9.8,12,7,12z"
/>
<path
d="M 3.5 3.5 L 7 3.5 A 3.5 3.5 0 {d} 1 {Math.cos(((2 * Math.PI) / count) * part - 0.01) * 3.5 + 3.5} {Math.sin(
((2 * Math.PI) / count) * part - 0.01
) *
3.5 +
3.5} Z"
transform="translate(3.5,3.5)"
/>
{:else if status === 'completed'}
{#if statusIcon.count && statusIcon.index}
<path
d="M 3.5 3.5 L 7 3.5 A 3.5 3.5 0 {statusIcon.index > (statusIcon.count - 1) / 2 ? 1 : 0} 1 {Math.cos(
((2 * Math.PI) / statusIcon.count) * statusIcon.index - 0.01
) *
3.5 +
3.5} {Math.sin(((2 * Math.PI) / statusIcon.count) * statusIcon.index - 0.01) * 3.5 + 3.5} Z"
transform="translate(3.5,3.5)"
/>
{:else}
<circle cx="7" cy="7" r="3.5" fill="var(--error-color)" opacity=".15" />
{/if}
{:else if category._id === tracker.issueStatusCategory.Completed}
<path
d="M7,0C3.1,0,0,3.1,0,7c0,3.9,3.1,7,7,7c3.9,0,7-3.1,7-7C14,3.1,10.9,0,7,0z M9.9,3.9c0.3-0.3,0.8-0.3,1.2,0l0,0c0.3,0.3,0.3,0.9,0,1.2l-5,5c-0.3,0.3-0.9,0.3-1.2,0l-2-2c-0.3-0.3-0.3-0.9,0-1.2c0.2-0.2,0.4-0.2,0.6-0.2s0.4,0.1,0.6,0.2l1.4,1.4l4-4v0L9.9,3.9z"
/>
{:else if status === 'canceled'}
{:else if category._id === tracker.issueStatusCategory.Canceled}
<path
style="fill-rule:evenodd;clip-rule:evenodd;"
d="M7,14c3.9,0,7-3.1,7-7c0-3.9-3.1-7-7-7C3.1,0,0,3.1,0,7C0,10.9,3.1,14,7,14z M5,4C4.7,3.7,4.3,3.7,4,4S3.7,4.7,4,5l2,2L4,9C3.7,9.3,3.7,9.7,4,10c0.3,0.3,0.8,0.3,1.1,0l2-2l2,2c0.3,0.3,0.8,0.3,1.1,0c0.3-0.3,0.3-0.8,0-1.1l-2-2l2-2c0.3-0.3,0.3-0.8,0-1.1C9.7,3.7,9.3,3.7,9,4l-2,2L5,4z"

View File

@ -13,11 +13,12 @@
// limitations under the License.
-->
<script lang="ts">
import { WithLookup } from '@anticrm/core'
import { WithLookup, SortingOrder } from '@anticrm/core'
import { getClient } from '@anticrm/presentation'
import { IssueStatus, IssueStatusCategory } from '@anticrm/tracker'
import { getPlatformColor, Icon, IconSize } from '@anticrm/ui'
import { getPlatformColor, IconSize } from '@anticrm/ui'
import tracker from '../../plugin'
import StatusIcon from '../icons/StatusIcon.svelte'
export let value: WithLookup<IssueStatus>
export let size: IconSize
@ -26,6 +27,11 @@
const client = getClient()
let category: IssueStatusCategory | undefined
let categories: IssueStatus[] | undefined
let statusIcon: {
index: number | undefined
count: number | undefined
} = { index: undefined, count: undefined }
async function updateCategory (status: WithLookup<IssueStatus>) {
if (status.$lookup?.category) {
@ -34,6 +40,19 @@
if (category === undefined) {
category = await client.findOne(tracker.class.IssueStatusCategory, { _id: value.category })
}
if (value.category === tracker.issueStatusCategory.Started) {
categories = await client.findAll(
tracker.class.IssueStatus,
{ category: tracker.issueStatusCategory.Started },
{ sort: { rank: SortingOrder.Ascending } }
)
if (categories) {
categories.map((cat, i) => {
if (cat._id === value._id) statusIcon = { index: i + 1, count: categories ? categories.length + 1 : 0 }
return true
})
}
}
}
$: updateCategory(value)
@ -45,6 +64,6 @@
'currentColor'
</script>
{#if icon !== undefined}
<Icon {icon} fill={color} {size} />
{#if icon !== undefined && color !== undefined && category !== undefined}
<StatusIcon {category} {size} fill={color} {statusIcon} />
{/if}

View File

@ -19,17 +19,7 @@
import notification from '@anticrm/notification'
import { createQuery } from '@anticrm/presentation'
import { Issue, IssuesGrouping, IssuesOrdering, IssueStatus, Team, ViewOptions } from '@anticrm/tracker'
import {
Button,
Component,
Icon,
IconAdd,
showPanel,
showPopup,
Loading,
tooltip,
getPlatformColor
} from '@anticrm/ui'
import { Button, Component, IconAdd, showPanel, showPopup, Loading, tooltip } from '@anticrm/ui'
import { focusStore, ListSelectionProvider, SelectDirection, selectionStore } from '@anticrm/view-resources'
import ActionContext from '@anticrm/view-resources/src/components/ActionContext.svelte'
import Menu from '@anticrm/view-resources/src/components/Menu.svelte'
@ -40,8 +30,7 @@
getKanbanStatuses,
getPriorityStates,
issuesGroupBySorting,
issuesSortOrderMap,
UNSET_COLOR
issuesSortOrderMap
} from '../../utils'
import CreateIssue from '../CreateIssue.svelte'
import ProjectEditor from '../projects/ProjectEditor.svelte'
@ -52,6 +41,7 @@
import PriorityEditor from './PriorityEditor.svelte'
import StatusEditor from './StatusEditor.svelte'
import tags from '@anticrm/tags'
import IssueStatusIcon from './IssueStatusIcon.svelte'
export let currentSpace: Ref<Team> = tracker.team.DefaultTeam
export let baseMenuClass: Ref<Class<Doc>> | undefined = undefined
@ -160,6 +150,9 @@
$: states = getIssueStates(groupBy, shouldShowEmptyGroups, issueStates, issueStatusStates, priorityStates)
const fullFilled: { [key: string]: boolean } = {}
const getState = (state: any): WithLookup<IssueStatus> | undefined => {
return issueStatuses?.filter((is) => is._id === state._id)[0]
}
</script>
{#if !states?.length}
@ -193,16 +186,11 @@
on:contextmenu={(evt) => showMenu(evt.detail.evt, evt.detail.objects)}
>
<svelte:fragment slot="header" let:state let:count>
{@const stateWLU = getState(state)}
<div class="header flex-col">
<div class="flex-between label font-medium w-full h-full">
<div class="flex-row-center gap-2">
{#if state.icon}
<Icon
icon={state.icon}
fill={state.color === UNSET_COLOR ? 'currentColor' : getPlatformColor(state.color)}
size="small"
/>
{/if}
{#if stateWLU !== undefined}<IssueStatusIcon value={stateWLU} size={'small'} />{/if}
<span class="lines-limit-2 ml-2">{state.title}</span>
<span class="counter ml-2 text-md">{count}</span>
</div>

View File

@ -17,9 +17,10 @@
import { AttachedData, Ref, SortingOrder, WithLookup } from '@anticrm/core'
import { Issue, IssueStatus } from '@anticrm/tracker'
import { createQuery, getClient } from '@anticrm/presentation'
import { Button, showPopup, SelectPopup, TooltipAlignment, eventToHTMLElement, getPlatformColor } from '@anticrm/ui'
import { Button, showPopup, SelectPopup, TooltipAlignment, eventToHTMLElement } from '@anticrm/ui'
import type { ButtonKind, ButtonSize } from '@anticrm/ui'
import tracker from '../../plugin'
import StatusPresenter from './StatusPresenter.svelte'
import IssueStatusIcon from './IssueStatusIcon.svelte'
export let value: Issue | AttachedData<Issue>
@ -64,14 +65,12 @@
$: selectedStatus = statuses?.find((status) => status._id === value.status) ?? statuses?.[0]
$: selectedStatusLabel = shouldShowLabel ? selectedStatus?.name : undefined
$: statusesInfo = statuses?.map((s) => {
const color = s.color ?? s.$lookup?.category?.color
$: statusesInfo = statuses?.map((s, i) => {
return {
id: s._id,
text: s.name,
icon: s.$lookup?.category?.icon,
...(color !== undefined ? { iconColor: getPlatformColor(color) } : undefined)
component: StatusPresenter,
props: { value: s, size: 'small' },
isSelected: selectedStatus?._id === s._id ?? false
}
})
$: if (!statuses) {
@ -112,12 +111,12 @@
{width}
on:click={handleStatusEditorOpened}
>
<span slot="content" class="inline-flex">
<span slot="content" class="inline-flex pointer-events-none">
{#if selectedStatus}
<IssueStatusIcon value={selectedStatus} size="inline" />
{/if}
{#if selectedStatusLabel}
<span class="overflow-label disabled" class:ml-1={selectedStatus}>{selectedStatusLabel}</span>
<span class="overflow-label disabled" class:ml-2={selectedStatus}>{selectedStatusLabel}</span>
{/if}
</span>
</Button>

View File

@ -18,12 +18,13 @@
import IssueStatusIcon from './IssueStatusIcon.svelte'
export let value: WithLookup<IssueStatus> | undefined
export let size: 'small' | 'medium' = 'medium'
</script>
{#if value}
<div class="flex-presenter">
{#if value.$lookup?.category?.icon}
<IssueStatusIcon {value} size="medium" />
<IssueStatusIcon {value} {size} />
{/if}
<span class="overflow-label" class:ml-2={value.$lookup?.category?.icon !== undefined}>
{value.name}

View File

@ -61,5 +61,5 @@
</script>
{#if loaded}
<Menu {actions} on:close />
<Menu {actions} on:close on:changeContent={() => dispatch('changeContent', true)} />
{/if}