mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-14 12:25:17 +00:00
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:
parent
bba0227a4f
commit
12da24f18c
@ -194,6 +194,7 @@
|
||||
.antiPopup {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: auto;
|
||||
min-height: 0;
|
||||
min-width: 0;
|
||||
max-width: 30rem;
|
||||
|
@ -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}
|
||||
|
@ -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" />
|
||||
|
@ -124,7 +124,9 @@
|
||||
on:fullsize={() => {
|
||||
fullSize = !fullSize
|
||||
}}
|
||||
on:changeContent={fitPopup}
|
||||
on:changeContent={() => {
|
||||
fitPopup()
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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)} />
|
||||
|
@ -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"
|
||||
|
@ -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}
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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}
|
||||
|
@ -61,5 +61,5 @@
|
||||
</script>
|
||||
|
||||
{#if loaded}
|
||||
<Menu {actions} on:close />
|
||||
<Menu {actions} on:close on:changeContent={() => dispatch('changeContent', true)} />
|
||||
{/if}
|
||||
|
Loading…
Reference in New Issue
Block a user