mirror of
https://github.com/hcengineering/platform.git
synced 2026-09-22 09:35:00 +02:00
Rework panel navigation (#928)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
@@ -15,15 +15,15 @@
|
||||
|
||||
<script lang="ts">
|
||||
|
||||
import type { Ref } from '@anticrm/core';
|
||||
import { getCurrentLocation,navigate } from '@anticrm/ui';
|
||||
import type { Application } from '@anticrm/workbench';
|
||||
import AppItem from './AppItem.svelte';
|
||||
import type { Ref } from '@anticrm/core'
|
||||
import { getCurrentLocation, navigate } from '@anticrm/ui'
|
||||
import type { Application } from '@anticrm/workbench'
|
||||
import AppItem from './AppItem.svelte'
|
||||
|
||||
export let active: Ref<Application> | undefined
|
||||
export let apps: Application[] = []
|
||||
|
||||
function navigateApp(app: Ref<Application>) {
|
||||
function navigateApp (app: Ref<Application>) {
|
||||
const loc = getCurrentLocation()
|
||||
loc.path[1] = app
|
||||
loc.path.length = 2
|
||||
@@ -34,6 +34,6 @@
|
||||
|
||||
<div class="flex-col">
|
||||
{#each apps as app}
|
||||
<AppItem selected={app._id === active} icon={app.icon} label={app.label} action={async () => {navigateApp(app._id)}}/>
|
||||
<AppItem selected={app._id === active} icon={app.icon} label={app.label} action={async () => { navigateApp(app._id) }} notify={false}/>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
@@ -25,7 +25,8 @@
|
||||
navigate,
|
||||
Popup,
|
||||
showPopup,
|
||||
TooltipInstance
|
||||
TooltipInstance,
|
||||
PanelInstance
|
||||
} from '@anticrm/ui'
|
||||
import type { Application, NavigatorModel, ViewConfiguration } from '@anticrm/workbench'
|
||||
import { onDestroy } from 'svelte'
|
||||
@@ -234,6 +235,7 @@
|
||||
</div>
|
||||
<!-- <div class="aside"><Chat thread/></div> -->
|
||||
</div>
|
||||
<PanelInstance/>
|
||||
<Popup />
|
||||
<TooltipInstance />
|
||||
{:else}
|
||||
|
||||
@@ -15,14 +15,12 @@
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import type { IntlString, Asset } from '@anticrm/platform'
|
||||
import type { Ref, Doc, Class, Space } from '@anticrm/core'
|
||||
import { IconClose, Label, EditBox, ToggleWithLabel, Grid, Icon } from '@anticrm/ui'
|
||||
import { getClient, createQuery, AttributeBarEditor } from '@anticrm/presentation'
|
||||
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
|
||||
import type { Class, Ref, Space } from '@anticrm/core'
|
||||
import core from '@anticrm/core'
|
||||
import type { IntlString } from '@anticrm/platform'
|
||||
import { createQuery, getClient } from '@anticrm/presentation'
|
||||
import { EditBox, Grid, Icon, IconClose, Label, ToggleWithLabel } from '@anticrm/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
|
||||
export let _id: Ref<Space>
|
||||
export let spaceClass: Ref<Class<Space>>
|
||||
@@ -43,7 +41,7 @@
|
||||
const tabs: IntlString[] = ['General' as IntlString, 'Members' as IntlString]
|
||||
let selected = 0
|
||||
|
||||
function onNameChange(ev: Event) {
|
||||
function onNameChange (ev: Event) {
|
||||
client.updateDoc(spaceClass, space.space, space._id, { name: (ev.target as HTMLInputElement).value })
|
||||
}
|
||||
|
||||
|
||||
@@ -71,20 +71,18 @@
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<TreeNode label={model.label} actions={[addSpace]}>
|
||||
<TreeNode label={model.label} actions={async () => [addSpace]}>
|
||||
{#each spaces as space}
|
||||
{#await getActions(space) then actions}
|
||||
<TreeItem
|
||||
_id={space._id}
|
||||
title={space.name}
|
||||
icon={classIcon(client, space._class)}
|
||||
selected={currentSpace === space._id}
|
||||
{actions}
|
||||
on:click={() => {
|
||||
selectSpace(space._id)
|
||||
}}
|
||||
/>
|
||||
{/await}
|
||||
<TreeItem
|
||||
_id={space._id}
|
||||
title={space.name}
|
||||
icon={classIcon(client, space._class)}
|
||||
selected={currentSpace === space._id}
|
||||
actions={() => getActions(space)}
|
||||
on:click={() => {
|
||||
selectSpace(space._id)
|
||||
}}
|
||||
/>
|
||||
{/each}
|
||||
</TreeNode>
|
||||
</div>
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import Collapsed from '../icons/Collapsed.svelte'
|
||||
import Expanded from '../icons/Expanded.svelte'
|
||||
@@ -31,18 +30,23 @@
|
||||
export let node = false
|
||||
export let collapsed = false
|
||||
export let selected = false
|
||||
export let actions: Action[] = []
|
||||
export let actions: () => Promise<Action[]> = async () => []
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let hovered = false
|
||||
function onMenuClick(ev: MouseEvent) {
|
||||
async function onMenuClick (ev: MouseEvent) {
|
||||
showPopup(Menu, { actions: await actions(), ctx: _id }, ev.target as HTMLElement, () => {
|
||||
hovered = false
|
||||
})
|
||||
hovered = true
|
||||
showPopup(Menu, { actions, ctx: _id }, ev.target as HTMLElement, () => { hovered = false })
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="container" class:selected class:hovered
|
||||
<div
|
||||
class="container"
|
||||
class:selected
|
||||
class:hovered
|
||||
on:click|stopPropagation={() => {
|
||||
if (node && !icon) collapsed = !collapsed
|
||||
dispatch('click')
|
||||
@@ -50,29 +54,42 @@
|
||||
>
|
||||
<div class="icon" class:sub={!node}>
|
||||
{#if icon}
|
||||
<Icon {icon} size={'small'}/>
|
||||
{:else}
|
||||
{#if collapsed}<Collapsed size={'small'} />{:else}<Expanded size={'small'} />{/if}
|
||||
{/if}
|
||||
<Icon {icon} size={'small'} />
|
||||
{:else if collapsed}<Collapsed size={'small'} />{:else}<Expanded size={'small'} />{/if}
|
||||
</div>
|
||||
<span class="label" class:sub={node}>
|
||||
{#if label}<Label {label}/>{:else}{title}{/if}
|
||||
{#if label}<Label {label} />{:else}{title}{/if}
|
||||
</span>
|
||||
{#if actions.length === 1}
|
||||
<div class="tool">
|
||||
<ActionIcon label={actions[0].label} icon={actions[0].icon} size={'small'} action={(ev) => { actions[0].action(_id, ev) }} />
|
||||
</div>
|
||||
{:else if actions.length > 1}
|
||||
{#if node === false}
|
||||
<div class="tool" on:click|stopPropagation={onMenuClick}>
|
||||
<IconMoreV size={'small'} />
|
||||
</div>
|
||||
{:else}
|
||||
{#await actions() then actionItems}
|
||||
{#if actionItems.length === 1}
|
||||
<div class="tool">
|
||||
<ActionIcon
|
||||
label={actionItems[0].label}
|
||||
icon={actionItems[0].icon}
|
||||
size={'small'}
|
||||
action={(ev) => {
|
||||
actionItems[0].action(_id, ev)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{:else if actionItems.length > 1}
|
||||
<div class="tool" on:click|stopPropagation={onMenuClick}>
|
||||
<IconMoreV size={'small'} />
|
||||
</div>
|
||||
{/if}
|
||||
{/await}
|
||||
{/if}
|
||||
{#if notifications > 0 && collapsed}
|
||||
<div class="counter">{notifications}</div>
|
||||
{/if}
|
||||
</div>
|
||||
{#if node && !icon && !collapsed}
|
||||
<div class="dropbox"><slot/></div>
|
||||
<div class="dropbox"><slot /></div>
|
||||
{/if}
|
||||
|
||||
<style lang="scss">
|
||||
@@ -81,19 +98,21 @@
|
||||
align-items: center;
|
||||
margin: 0 1rem;
|
||||
height: 2.25rem;
|
||||
border-radius: .5rem;
|
||||
border-radius: 0.5rem;
|
||||
user-select: none;
|
||||
cursor: pointer;
|
||||
|
||||
.icon {
|
||||
min-width: 1rem;
|
||||
color: var(--theme-content-trans-color);
|
||||
margin: 0 1.125rem 0 .625rem;
|
||||
&.sub { margin: 0 .5rem 0 2.75rem }
|
||||
margin: 0 1.125rem 0 0.625rem;
|
||||
&.sub {
|
||||
margin: 0 0.5rem 0 2.75rem;
|
||||
}
|
||||
}
|
||||
.label {
|
||||
flex-grow: 1;
|
||||
margin-right: .75rem;
|
||||
margin-right: 0.75rem;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
@@ -106,31 +125,34 @@
|
||||
}
|
||||
}
|
||||
.tool {
|
||||
margin-right: .75rem;
|
||||
margin-right: 0.75rem;
|
||||
visibility: hidden;
|
||||
}
|
||||
.counter {
|
||||
margin-right: .75rem;
|
||||
margin-right: 0.75rem;
|
||||
font-weight: 600;
|
||||
font-size: .75rem;
|
||||
font-size: 0.75rem;
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
|
||||
&:hover, &.hovered {
|
||||
&:hover,
|
||||
&.hovered {
|
||||
background-color: var(--theme-button-bg-enabled);
|
||||
.tool {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
&.selected {
|
||||
background-color: var(--theme-menu-selection);
|
||||
&:hover { background-color: var(--theme-button-bg-enabled); }
|
||||
&:hover {
|
||||
background-color: var(--theme-button-bg-enabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dropbox {
|
||||
height: auto;
|
||||
margin-bottom: .5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -24,11 +24,11 @@
|
||||
export let icon: Asset
|
||||
export let title: string
|
||||
export let notifications = 0
|
||||
export let actions: Action[] = []
|
||||
export let actions: () => Promise<Action[]> = async () => []
|
||||
export let selected: boolean = false
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
</script>
|
||||
|
||||
<TreeElement {_id} {icon} {title} {notifications} {selected} {actions} collapsed on:click={() => {dispatch('click')}}/>
|
||||
<TreeElement {_id} {icon} {title} {notifications} {selected} {actions} collapsed on:click={() => { dispatch('click') }}/>
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
import TreeElement from './TreeElement.svelte'
|
||||
|
||||
export let label: IntlString
|
||||
export let actions: Action[] = []
|
||||
export let actions: () => Promise<Action[]> = async () => []
|
||||
export let notifications = 0
|
||||
export let collapsed = false
|
||||
|
||||
|
||||
Reference in New Issue
Block a user