mirror of
https://github.com/hcengineering/platform.git
synced 2026-09-13 13:17:45 +02:00
Updated navigator layout (#5619)
Signed-off-by: Alexander Platov <alexander.platov@hardcoreeng.com>
This commit is contained in:
@@ -32,7 +32,7 @@
|
||||
export let documentById: Map<Ref<Document>, Document>
|
||||
|
||||
export let selected: Ref<Document> | undefined
|
||||
export let level = 1
|
||||
export let level: number = 0
|
||||
|
||||
const client = getClient()
|
||||
const dispatch = createEventDispatcher()
|
||||
@@ -97,10 +97,12 @@
|
||||
}}
|
||||
title={doc.name}
|
||||
selected={selected === doc._id}
|
||||
parent={desc.length > 0}
|
||||
isFold
|
||||
{level}
|
||||
empty={desc.length === 0}
|
||||
actions={getActions(doc)}
|
||||
moreActions={() => getMoreActions(doc)}
|
||||
{level}
|
||||
shouldTooltip
|
||||
on:click={() => {
|
||||
handleDocumentSelected(doc._id)
|
||||
}}
|
||||
|
||||
@@ -17,19 +17,7 @@
|
||||
import { Document } from '@hcengineering/document'
|
||||
import type { Asset, IntlString } from '@hcengineering/platform'
|
||||
import type { Action, AnySvelteComponent } from '@hcengineering/ui'
|
||||
import {
|
||||
ActionIcon,
|
||||
Icon,
|
||||
IconChevronDown,
|
||||
IconMoreH,
|
||||
Label,
|
||||
Menu,
|
||||
navigate,
|
||||
showPopup,
|
||||
getTreeCollapsed,
|
||||
setTreeCollapsed
|
||||
} from '@hcengineering/ui'
|
||||
|
||||
import { IconMoreH, Menu, navigate, showPopup, NavItem, ButtonIcon } from '@hcengineering/ui'
|
||||
import { getDocumentLink } from '../../utils'
|
||||
|
||||
export let doc: Document
|
||||
@@ -37,14 +25,16 @@
|
||||
export let iconProps: Record<string, any> | undefined = undefined
|
||||
export let label: IntlString | undefined = undefined
|
||||
export let title: string | undefined = undefined
|
||||
export let parent: boolean = false
|
||||
export let collapsed: boolean = getTreeCollapsed(doc._id)
|
||||
export let selected: boolean = false
|
||||
export let isFold: boolean = false
|
||||
export let empty: boolean = false
|
||||
export let shouldTooltip: boolean = false
|
||||
export let level: number = 0
|
||||
export let actions: Action[] = []
|
||||
export let moreActions: (originalEvent?: MouseEvent) => Promise<Action[]> | undefined = async () => []
|
||||
export let forciblyСollapsed: boolean = false
|
||||
|
||||
let hovered = false
|
||||
let hovered: boolean = false
|
||||
async function onMenuClick (ev: MouseEvent): Promise<void> {
|
||||
showPopup(Menu, { actions: await moreActions(ev), ctx: doc._id }, ev.target as HTMLElement, () => {
|
||||
hovered = false
|
||||
@@ -58,59 +48,41 @@
|
||||
}
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
$: collapsed = getTreeCollapsed(doc._id)
|
||||
$: setTreeCollapsed(doc._id, collapsed)
|
||||
</script>
|
||||
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div
|
||||
class="antiNav-element tree"
|
||||
class:selected
|
||||
class:hovered
|
||||
class:parent
|
||||
class:collapsed
|
||||
style:padding-left={`${level > 0 ? level * 1.25 + 0.125 : 0.75}rem`}
|
||||
<NavItem
|
||||
_id={doc._id}
|
||||
{icon}
|
||||
{iconProps}
|
||||
{label}
|
||||
{title}
|
||||
{isFold}
|
||||
{level}
|
||||
{empty}
|
||||
{selected}
|
||||
showMenu={hovered}
|
||||
{shouldTooltip}
|
||||
{forciblyСollapsed}
|
||||
on:click={() => {
|
||||
selectDocument()
|
||||
if (selected) {
|
||||
collapsed = !collapsed
|
||||
}
|
||||
dispatch('click')
|
||||
}}
|
||||
>
|
||||
<div
|
||||
class="an-element__tool arrow"
|
||||
class:empty={!parent}
|
||||
on:click|preventDefault|stopPropagation={() => {
|
||||
if (parent) collapsed = !collapsed
|
||||
}}
|
||||
>
|
||||
{#if parent}<IconChevronDown size={'small'} filled />{/if}
|
||||
</div>
|
||||
|
||||
{#if icon}
|
||||
<div class="an-element__icon" class:folder={level === 0}>
|
||||
<Icon {icon} {iconProps} size={'small'} />
|
||||
</div>
|
||||
{/if}
|
||||
<span class="an-element__label">
|
||||
{#if label}<Label {label} />{:else}{title}{/if}
|
||||
</span>
|
||||
<div class="an-element__grow" />
|
||||
|
||||
{#each actions as action}
|
||||
{#if action.icon}
|
||||
<div class="an-element__tool">
|
||||
<ActionIcon label={action.label} icon={action.icon} size={'small'} action={(evt) => action.action({}, evt)} />
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
<div class="an-element__tool" class:pressed={hovered} on:click|preventDefault|stopPropagation={onMenuClick}>
|
||||
<IconMoreH size={'small'} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if parent && !collapsed}
|
||||
<div class="antiNav-element__dropbox"><slot /></div>
|
||||
{/if}
|
||||
<svelte:fragment slot="actions">
|
||||
{#each actions as action}
|
||||
{#if action.icon}
|
||||
<ButtonIcon
|
||||
icon={action.icon}
|
||||
kind={'tertiary'}
|
||||
size={'extra-small'}
|
||||
tooltip={{ label: action.label, direction: 'top' }}
|
||||
on:click={(evt) => action.action({}, evt)}
|
||||
/>
|
||||
{/if}
|
||||
{/each}
|
||||
<ButtonIcon icon={IconMoreH} kind={'tertiary'} size={'extra-small'} pressed={hovered} on:click={onMenuClick} />
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="dropbox">
|
||||
<slot />
|
||||
</svelte:fragment>
|
||||
</NavItem>
|
||||
|
||||
+74
-13
@@ -13,25 +13,27 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Ref, SortingOrder, Space } from '@hcengineering/core'
|
||||
import { Ref, SortingOrder, Space, generateId } from '@hcengineering/core'
|
||||
import { Document, Teamspace } from '@hcengineering/document'
|
||||
import { createQuery } from '@hcengineering/presentation'
|
||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import {
|
||||
IconWithEmoji,
|
||||
getTreeCollapsed,
|
||||
setTreeCollapsed,
|
||||
IconEdit,
|
||||
getPlatformColorDef,
|
||||
getPlatformColorForTextDef,
|
||||
themeStore,
|
||||
Action
|
||||
Action,
|
||||
IconAdd
|
||||
} from '@hcengineering/ui'
|
||||
import view from '@hcengineering/view'
|
||||
import { TreeNode } from '@hcengineering/view-resources'
|
||||
import { TreeNode, openDoc, getActions as getContributedActions } from '@hcengineering/view-resources'
|
||||
import { SpacesNavModel } from '@hcengineering/workbench'
|
||||
import { getResource } from '@hcengineering/platform'
|
||||
|
||||
import document from '../../plugin'
|
||||
import { getDocumentIdFromFragment } from '../../utils'
|
||||
import { getDocumentIdFromFragment, createEmptyDocument } from '../../utils'
|
||||
import DocHierarchy from './DocHierarchy.svelte'
|
||||
import DocTreeElement from './DocTreeElement.svelte'
|
||||
|
||||
export let space: Teamspace
|
||||
export let model: SpacesNavModel
|
||||
@@ -40,9 +42,9 @@
|
||||
export let currentFragment: string | undefined
|
||||
export let getActions: (space: Space) => Promise<Action[]> = async () => []
|
||||
export let deselect: boolean = false
|
||||
export let forciblyСollapsed: boolean = false
|
||||
|
||||
let collapsed: boolean = getTreeCollapsed(space._id)
|
||||
$: setTreeCollapsed(space._id, collapsed)
|
||||
const client = getClient()
|
||||
|
||||
let documents: Ref<Document>[] = []
|
||||
let documentById: Map<Ref<Document>, Document> = new Map<Ref<Document>, Document>()
|
||||
@@ -54,6 +56,8 @@
|
||||
|
||||
let selected: Ref<Document> | undefined
|
||||
$: selected = getDocumentIdFromFragment(currentFragment ?? '')
|
||||
let visibleItem: Document | undefined
|
||||
$: visibleItem = selected !== undefined ? documentById.get(selected) : undefined
|
||||
|
||||
// TODO expand tree until the selected document ?
|
||||
|
||||
@@ -84,10 +88,43 @@
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
function getDocActions (doc: Document): Action[] {
|
||||
return [
|
||||
{
|
||||
icon: IconAdd,
|
||||
label: document.string.CreateDocument,
|
||||
action: async (ctx: any, evt: Event) => {
|
||||
const id: Ref<Document> = generateId()
|
||||
await createEmptyDocument(client, id, doc.space, doc._id, {})
|
||||
|
||||
const object = await client.findOne(document.class.Document, { _id: id })
|
||||
if (object !== undefined) {
|
||||
openDoc(client.getHierarchy(), object)
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
async function getMoreActions (obj: Document): Promise<Action[]> {
|
||||
const result: Action[] = []
|
||||
const extraActions = await getContributedActions(client, obj)
|
||||
for (const act of extraActions) {
|
||||
result.push({
|
||||
icon: act.icon ?? IconEdit,
|
||||
label: act.label,
|
||||
action: async (ctx: any, evt: Event) => {
|
||||
const impl = await getResource(act.action)
|
||||
await impl(obj, evt, act.actionProps)
|
||||
}
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
</script>
|
||||
|
||||
<TreeNode
|
||||
{collapsed}
|
||||
_id={space?._id}
|
||||
icon={space?.icon === view.ids.IconWithEmoji ? IconWithEmoji : space?.icon ?? model.icon}
|
||||
iconProps={space?.icon === view.ids.IconWithEmoji
|
||||
@@ -99,10 +136,34 @@
|
||||
: getPlatformColorForTextDef(space.name, $themeStore.dark).icon
|
||||
}}
|
||||
title={space.name}
|
||||
folder
|
||||
parent={descendants.size > 0}
|
||||
type={'nested'}
|
||||
highlighted={currentSpace === space._id}
|
||||
visible={currentSpace === space._id || forciblyСollapsed}
|
||||
actions={() => getActions(space)}
|
||||
on:click={() => (collapsed = !collapsed)}
|
||||
{forciblyСollapsed}
|
||||
>
|
||||
<DocHierarchy {documents} {descendants} {documentById} {selected} />
|
||||
|
||||
<svelte:fragment slot="visible">
|
||||
{#if (selected || forciblyСollapsed) && visibleItem}
|
||||
{@const item = visibleItem}
|
||||
<DocTreeElement
|
||||
doc={item}
|
||||
icon={item.icon === view.ids.IconWithEmoji ? IconWithEmoji : item.icon ?? document.icon.Document}
|
||||
iconProps={item.icon === view.ids.IconWithEmoji
|
||||
? { icon: visibleItem.color }
|
||||
: {
|
||||
fill: item.color !== undefined ? getPlatformColorDef(item.color, $themeStore.dark).icon : 'currentColor'
|
||||
}}
|
||||
title={item.name}
|
||||
selected
|
||||
isFold
|
||||
empty
|
||||
shouldTooltip
|
||||
actions={getDocActions(item)}
|
||||
moreActions={() => getMoreActions(item)}
|
||||
forciblyСollapsed
|
||||
/>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</TreeNode>
|
||||
|
||||
Reference in New Issue
Block a user