mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-25 09:50:19 +00:00
Add additional panel display modes (#1279)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
parent
859640ca5e
commit
0b93f86dfd
@ -15,12 +15,12 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import activity from '@anticrm/activity'
|
||||
import calendar from '@anticrm/calendar'
|
||||
import type { Doc } from '@anticrm/core'
|
||||
import notification from '@anticrm/notification'
|
||||
import calendar from '@anticrm/calendar'
|
||||
import type { Asset } from '@anticrm/platform'
|
||||
import { ActionIcon,AnyComponent,AnySvelteComponent,Component,Icon,IconClose,IconExpand,IconMoreH,Scroller } from '@anticrm/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { ActionIcon, AnyComponent, AnySvelteComponent, Component, IconExpand, Panel, Scroller } from '@anticrm/ui'
|
||||
import { PopupAlignment } from '@anticrm/ui'
|
||||
|
||||
export let title: string
|
||||
export let subtitle: string | undefined = undefined
|
||||
@ -28,72 +28,53 @@
|
||||
export let fullSize: boolean = true
|
||||
export let rightSection: AnyComponent | undefined = undefined
|
||||
export let object: Doc
|
||||
export let position: PopupAlignment | undefined = undefined
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
let innerWidth = 0
|
||||
|
||||
$: allowFullSize = innerWidth > 900 && position === 'full'
|
||||
$: isFullSize = allowFullSize && fullSize
|
||||
</script>
|
||||
|
||||
<div class="antiOverlay" on:click={() => { dispatch('close') }} />
|
||||
<div class="antiDialogs antiComponent" class:fullSize>
|
||||
{#if fullSize}
|
||||
<div class="ad-section-50 divide">
|
||||
<div class="ac-header short mirror divide">
|
||||
<div class="ac-header__wrap-title">
|
||||
{#if icon }<div class="ac-header__icon"><Icon {icon} size={'large'}/></div>{/if}
|
||||
<div class="ac-header__wrap-description">
|
||||
<span class="ac-header__title">{title}</span>
|
||||
{#if subtitle }<span class="ac-header__description">{subtitle}</span>{/if}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<Component is={calendar.component.DocReminder} props={{ value: object, title }} />
|
||||
<div class="ml-2">
|
||||
<Component is={notification.component.LastViewEditor} props={{ value: object }} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{#if $$slots.subtitle}
|
||||
<div class="ac-subtitle">
|
||||
<div class="ac-subtitle-content">
|
||||
<slot name="subtitle" />
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<Scroller>
|
||||
<div class="p-10"><slot /></div>
|
||||
</Scroller>
|
||||
</div>
|
||||
<div class="ad-section-50">
|
||||
<Component is={rightSection ?? activity.component.Activity} props={{ object, fullSize }} />
|
||||
</div>
|
||||
{:else}
|
||||
<div class="ac-header short mirror-tool divide">
|
||||
<div class="ac-header__wrap-title">
|
||||
{#if icon }<div class="ac-header__icon"><Icon {icon} size={'large'}/></div>{/if}
|
||||
<div class="ac-header__wrap-description">
|
||||
<span class="ac-header__title">{title}</span>
|
||||
{#if subtitle }<span class="ac-header__description">{subtitle}</span>{/if}
|
||||
</div>
|
||||
</div>
|
||||
<svelte:window bind:innerWidth />
|
||||
<Panel {title} {subtitle} {icon} on:close rightSection={isFullSize}>
|
||||
<svelte:fragment slot="subtitle">
|
||||
<slot name="subtitle" />
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="commands">
|
||||
<Component is={calendar.component.DocReminder} props={{ value: object, title }} />
|
||||
<div class="ml-2">
|
||||
<Component is={notification.component.LastViewEditor} props={{ value: object }} />
|
||||
</div>
|
||||
{#if $$slots.subtitle}
|
||||
<div class="ac-subtitle">
|
||||
<div class="ac-subtitle-content">
|
||||
<slot name="subtitle" />
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
|
||||
<svelte:fragment slot="rightSection">
|
||||
{#if isFullSize}
|
||||
<div class="ad-section-50">
|
||||
<Component is={rightSection ?? activity.component.Activity} props={{ object, fullSize: isFullSize }} />
|
||||
</div>
|
||||
{/if}
|
||||
<Component is={activity.component.Activity} props={{ object, fullSize }}>
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="actions">
|
||||
{#if allowFullSize}
|
||||
<div class="tool">
|
||||
<ActionIcon
|
||||
icon={IconExpand}
|
||||
size={'medium'}
|
||||
action={() => {
|
||||
fullSize = !fullSize
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
{#if isFullSize}
|
||||
<Scroller>
|
||||
<div class="p-10"><slot /></div>
|
||||
</Scroller>
|
||||
{:else}
|
||||
<Component is={activity.component.Activity} props={{ object, fullSize: isFullSize }}>
|
||||
<slot />
|
||||
</Component>
|
||||
{/if}
|
||||
</Panel>
|
||||
|
||||
<div class="ad-tools">
|
||||
<div class="tool">
|
||||
<ActionIcon icon={IconExpand} size={'medium'} action={() => { fullSize = !fullSize }} />
|
||||
</div>
|
||||
<div class="tool">
|
||||
<ActionIcon icon={IconClose} size={'medium'} action={() => { dispatch('close') }} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -20,6 +20,7 @@
|
||||
@import "./dialogs.scss";
|
||||
@import "./popups.scss";
|
||||
@import "./mixins.scss";
|
||||
@import "./panel.scss";
|
||||
|
||||
@font-face {
|
||||
font-family: 'IBM Plex Sans';
|
||||
|
59
packages/theme/styles/panel.scss
Normal file
59
packages/theme/styles/panel.scss
Normal file
@ -0,0 +1,59 @@
|
||||
//
|
||||
// Copyright © 2022 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.
|
||||
//
|
||||
|
||||
/* Dialogs */
|
||||
.antiPanel {
|
||||
overflow: hidden;
|
||||
min-width: 400px;
|
||||
|
||||
background: var(--popup-bg-color);
|
||||
border-radius: .5rem;
|
||||
flex-direction: row;
|
||||
// left: 1rem;
|
||||
|
||||
.ac-header.divide { border-bottom: 1px solid var(--theme-card-divider); }
|
||||
|
||||
.ad-section-50 {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-basis: 50%;
|
||||
min-height: 0;
|
||||
width: 50%;
|
||||
|
||||
&.divide { border-right: 1px solid var(--theme-card-divider); }
|
||||
}
|
||||
|
||||
.ad-tools {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
top: 1rem;
|
||||
right: 2rem;
|
||||
&.grow-reverse {
|
||||
left: 0px;
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
.tool {
|
||||
margin-left: 1rem;
|
||||
color: var(--theme-content-accent-color);
|
||||
cursor: pointer;
|
||||
|
||||
&:hover { color: var(--theme-caption-color); }
|
||||
}
|
||||
}
|
||||
|
91
packages/ui/src/components/Panel.svelte
Normal file
91
packages/ui/src/components/Panel.svelte
Normal file
@ -0,0 +1,91 @@
|
||||
<!--
|
||||
// Copyright © 2022 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">
|
||||
import type { Asset } from '@anticrm/platform'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { AnySvelteComponent } from '../types'
|
||||
import ActionIcon from './ActionIcon.svelte'
|
||||
import Icon from './Icon.svelte'
|
||||
import IconClose from './icons/Close.svelte'
|
||||
|
||||
export let title: string | undefined = undefined
|
||||
export let subtitle: string | undefined = undefined
|
||||
export let icon: Asset | AnySvelteComponent | undefined = undefined
|
||||
export let rightSection: boolean = false
|
||||
export let reverseCommands = false
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
</script>
|
||||
|
||||
<div class="antiPanel antiComponent">
|
||||
<div class:panel-content={!rightSection} class:ad-section-50={rightSection} class:divide={rightSection}>
|
||||
<div class="ac-header short mirror divide">
|
||||
<div class="ac-header__wrap-title">
|
||||
{#if icon}<div class="ac-header__icon"><Icon {icon} size={'large'} /></div>{/if}
|
||||
<div class="ac-header__wrap-description">
|
||||
{#if title}
|
||||
<span class="ac-header__title">{title}</span>
|
||||
{/if}
|
||||
{#if subtitle}<span class="ac-header__description">{subtitle}</span>{/if}
|
||||
</div>
|
||||
</div>
|
||||
{#if rightSection}
|
||||
<div class="flex">
|
||||
<slot name="commands" />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{#if $$slots.subtitle}
|
||||
<div class="ac-subtitle">
|
||||
<div class="ac-subtitle-content">
|
||||
<slot name="subtitle" />
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<div class='flex-col'>
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if rightSection}
|
||||
<slot name='rightSection'/>
|
||||
{/if}
|
||||
|
||||
<div class="ad-tools" class:grow-reverse={reverseCommands}>
|
||||
{#if !rightSection && $$slots.commands}
|
||||
<div class="flex">
|
||||
<slot name="commands" />
|
||||
</div>
|
||||
{/if}
|
||||
<slot name='actions'/>
|
||||
<div class="tool">
|
||||
<ActionIcon
|
||||
icon={IconClose}
|
||||
size={'medium'}
|
||||
action={() => {
|
||||
dispatch('close')
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<style lang="scss">
|
||||
.panel-content {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
flex-direction: column;
|
||||
align-content: stretch;
|
||||
}
|
||||
</style>
|
@ -17,9 +17,11 @@
|
||||
import { getResource } from '@anticrm/platform'
|
||||
import { afterUpdate } from 'svelte'
|
||||
import { AnySvelteComponent, Spinner } from '..'
|
||||
import { closePanel, PanelProps, panelstore as modal } from '../panelup'
|
||||
import { closePanel, PanelProps, panelstore } from '../panelup'
|
||||
import { popupstore } from '../popups'
|
||||
|
||||
export let contentPanel: HTMLElement
|
||||
|
||||
let modalHTML: HTMLElement
|
||||
let componentInstance: any
|
||||
let show: boolean = false
|
||||
@ -31,7 +33,7 @@
|
||||
closePanel()
|
||||
}
|
||||
|
||||
$: props = $modal.panel
|
||||
$: props = $panelstore.panel
|
||||
|
||||
$: if (props !== undefined) {
|
||||
getResource(props.component).then((r) => {
|
||||
@ -51,7 +53,7 @@
|
||||
_close()
|
||||
}
|
||||
|
||||
const fitPopup = (props: PanelProps): void => {
|
||||
const fitPopup = (props: PanelProps, contentPanel: HTMLElement): void => {
|
||||
if (modalHTML) {
|
||||
if (props.element) {
|
||||
show = false
|
||||
@ -76,10 +78,11 @@
|
||||
} else {
|
||||
modalHTML.style.left = rect.left + 'px'
|
||||
}
|
||||
} else if (props.element === 'right') {
|
||||
modalHTML.style.top = '0'
|
||||
modalHTML.style.bottom = '0'
|
||||
modalHTML.style.right = '0'
|
||||
} else if (props.element === 'right' && contentPanel !== undefined) {
|
||||
const rect = contentPanel.getBoundingClientRect()
|
||||
modalHTML.style.top = `calc(${rect.top}px + 0.5rem)`
|
||||
modalHTML.style.bottom = '0.75rem'
|
||||
modalHTML.style.right = '0.75rem'
|
||||
} else if (props.element === 'float') {
|
||||
modalHTML.style.top = '4rem'
|
||||
modalHTML.style.bottom = '4rem'
|
||||
@ -87,11 +90,24 @@
|
||||
} else if (props.element === 'account') {
|
||||
modalHTML.style.bottom = '2.75rem'
|
||||
modalHTML.style.left = '5rem'
|
||||
} else if (props.element === 'full') {
|
||||
modalHTML.style.top = '0'
|
||||
modalHTML.style.bottom = '0'
|
||||
modalHTML.style.left = '0'
|
||||
modalHTML.style.right = '0'
|
||||
} else if (props.element === 'full' && contentPanel !== undefined) {
|
||||
const rect = contentPanel.getBoundingClientRect()
|
||||
modalHTML.style.top = `calc(${rect.top}px + 0.5rem)`
|
||||
modalHTML.style.bottom = '0.75rem'
|
||||
modalHTML.style.left = '0.75rem'
|
||||
modalHTML.style.right = '0.75rem'
|
||||
} else if (props.element === 'content' && contentPanel !== undefined) {
|
||||
const rect = contentPanel.getBoundingClientRect()
|
||||
modalHTML.style.top = `calc(${rect.top}px + 0.5rem)`
|
||||
modalHTML.style.bottom = '0.75rem'
|
||||
modalHTML.style.left = `calc(${rect.left}px + 0.5rem)`
|
||||
modalHTML.style.right = '0.75rem'
|
||||
} else if (props.element === 'middle' && contentPanel !== undefined) {
|
||||
const rect = contentPanel.getBoundingClientRect()
|
||||
modalHTML.style.top = `calc(${rect.top}px + 0.5rem)`
|
||||
modalHTML.style.bottom = '0.75rem'
|
||||
modalHTML.style.left = '50%'
|
||||
modalHTML.style.transform = 'translateX(-50%)'
|
||||
}
|
||||
} else {
|
||||
modalHTML.style.top = '50%'
|
||||
@ -108,13 +124,13 @@
|
||||
}
|
||||
}
|
||||
afterUpdate(() => {
|
||||
if (props) fitPopup(props)
|
||||
if (props) fitPopup(props, contentPanel)
|
||||
})
|
||||
</script>
|
||||
|
||||
<svelte:window
|
||||
on:resize={() => {
|
||||
if (props) fitPopup(props)
|
||||
if (props) fitPopup(props, contentPanel)
|
||||
}}
|
||||
on:keydown={(evt) => {
|
||||
if (props) handleKeydown(evt)
|
||||
@ -123,29 +139,33 @@
|
||||
{#if props}
|
||||
{#if !component}
|
||||
<Spinner />
|
||||
{:else}
|
||||
<div class="popup" bind:this={modalHTML} style={'z-index: 401'}>
|
||||
{:else}
|
||||
<div class="antiPanel panel-instance" bind:this={modalHTML}>
|
||||
<svelte:component
|
||||
this={component}
|
||||
bind:this={componentInstance}
|
||||
_id={props._id}
|
||||
_class={props._class}
|
||||
rightSection={props.rightSection}
|
||||
on:update={fitPopup}
|
||||
position={props.element }
|
||||
on:close={_close}
|
||||
on:update={() => {
|
||||
if (props) {
|
||||
fitPopup(props, contentPanel)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div class="modal-overlay" class:show style={'z-index: 400'} on:click={() => escapeClose()} />
|
||||
{#if props.element !== 'content'}
|
||||
<div class="modal-overlay" class:show style={'z-index: 400'} on:click={() => escapeClose()} />
|
||||
{/if}
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
<style lang="scss">
|
||||
.popup {
|
||||
.panel-instance {
|
||||
z-index: 401;
|
||||
position: fixed;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
max-height: calc(100vh - 2rem);
|
||||
background-color: transparent;
|
||||
}
|
||||
.modal-overlay {
|
||||
|
@ -20,7 +20,7 @@ import { readable } from 'svelte/store'
|
||||
|
||||
import Root from './components/internal/Root.svelte'
|
||||
|
||||
export type { AnyComponent, AnySvelteComponent, Action, LabelAndProps, TooltipAligment, AnySvelteComponentWithProps, Location } from './types'
|
||||
export type { AnyComponent, AnySvelteComponent, Action, LabelAndProps, TooltipAligment, AnySvelteComponentWithProps, Location, PopupAlignment } from './types'
|
||||
// export { applicationShortcutKey } from './utils'
|
||||
export { getCurrentLocation, locationToUrl, navigate, location } from './location'
|
||||
|
||||
@ -97,6 +97,7 @@ export { default as IconCheck } from './components/icons/Check.svelte'
|
||||
export { default as IconArrowLeft } from './components/icons/ArrowLeft.svelte'
|
||||
|
||||
export { default as PanelInstance } from './components/PanelInstance.svelte'
|
||||
export { default as Panel } from './components/Panel.svelte'
|
||||
|
||||
export * from './utils'
|
||||
export * from './popups'
|
||||
|
@ -63,7 +63,7 @@ export interface Tab {
|
||||
|
||||
export type TabModel = Tab[]
|
||||
|
||||
export type PopupAlignment = HTMLElement | EventTarget | null | 'right' | 'float' | 'account' | 'full'
|
||||
export type PopupAlignment = HTMLElement | EventTarget | null | 'right' | 'float' | 'account' | 'full' | 'content' | 'middle'
|
||||
|
||||
export type TooltipAligment = 'top' | 'bottom' | 'left' | 'right'
|
||||
|
||||
|
@ -23,7 +23,7 @@
|
||||
export let inline: boolean = false
|
||||
|
||||
async function show () {
|
||||
showPanel(view.component.EditDoc, value._id, value._class, 'full')
|
||||
showPanel(view.component.EditDoc, value._id, value._class, 'middle')
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -33,7 +33,7 @@
|
||||
}
|
||||
|
||||
function showLead () {
|
||||
showPanel(view.component.EditDoc, object._id, object._class, 'full')
|
||||
showPanel(view.component.EditDoc, object._id, object._class, 'middle')
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -48,6 +48,7 @@
|
||||
"@anticrm/contact": "~0.6.5",
|
||||
"@anticrm/view-resources": "~0.6.0",
|
||||
"lexorank": "~1.0.4",
|
||||
"@anticrm/text-editor": "~0.6.0"
|
||||
"@anticrm/text-editor": "~0.6.0",
|
||||
"@anticrm/panel": "~0.6.0"
|
||||
}
|
||||
}
|
||||
|
@ -15,21 +15,44 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import contact from '@anticrm/contact'
|
||||
import { getClient, UserBox } from '@anticrm/presentation'
|
||||
import type { Issue } from '@anticrm/tracker'
|
||||
import { Class, Ref } from '@anticrm/core'
|
||||
import { createQuery, getClient, UserBox } from '@anticrm/presentation'
|
||||
import { StyledTextBox } from '@anticrm/text-editor'
|
||||
import { EditBox, Grid } from '@anticrm/ui'
|
||||
import type { Issue, Team } from '@anticrm/tracker'
|
||||
import { AnyComponent, Button, EditBox, Grid, IconDown, IconUp } from '@anticrm/ui'
|
||||
import { createEventDispatcher, onMount } from 'svelte'
|
||||
import tracker from '../../plugin'
|
||||
import Card from '../Card.svelte'
|
||||
// import Card from '../Card.svelte'
|
||||
import { Panel } from '@anticrm/ui'
|
||||
import IssuePresenter from './IssuePresenter.svelte'
|
||||
|
||||
export let object: Issue
|
||||
export let _id: Ref<Issue>
|
||||
export let _class: Ref<Class<Issue>>
|
||||
export let rightSection: AnyComponent | undefined = undefined
|
||||
|
||||
let object: Issue | undefined
|
||||
|
||||
let currentTeam: Team | undefined
|
||||
|
||||
const query = createQuery()
|
||||
$: _id &&
|
||||
_class &&
|
||||
query.query(_class, { _id }, async (result) => {
|
||||
object = result[0]
|
||||
})
|
||||
|
||||
$: if (object !== undefined) {
|
||||
client.findOne(tracker.class.Team, { _id: object.space }).then((r) => {
|
||||
currentTeam = r
|
||||
})
|
||||
}
|
||||
const dispatch = createEventDispatcher()
|
||||
const client = getClient()
|
||||
|
||||
function change (field: string, value: any) {
|
||||
client.update(object, { [field]: value })
|
||||
if (object !== undefined) {
|
||||
client.update(object, { [field]: value })
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
@ -37,44 +60,62 @@
|
||||
})
|
||||
</script>
|
||||
|
||||
<Card
|
||||
label={tracker.string.NewIssue}
|
||||
okAction={() => {}}
|
||||
canSave={true}
|
||||
on:close={() => {
|
||||
dispatch('close')
|
||||
}}
|
||||
>
|
||||
{#if object !== undefined}
|
||||
<Grid column={1} rowGap={1.5}>
|
||||
<EditBox
|
||||
label={tracker.string.Title}
|
||||
bind:value={object.title}
|
||||
placeholder={tracker.string.IssueTitlePlaceholder}
|
||||
maxWidth={'16rem'}
|
||||
focus
|
||||
on:change={() => change('title', object.title) }
|
||||
/>
|
||||
<StyledTextBox alwaysEdit bind:content={object.description} placeholder={tracker.string.IssueDescriptionPlaceholder}
|
||||
on:value={(evt) => change('description', evt.detail) }/>
|
||||
<UserBox
|
||||
_class={contact.class.Employee}
|
||||
title={tracker.string.Assignee}
|
||||
caption={tracker.string.Assignee}
|
||||
bind:value={object.assignee}
|
||||
allowDeselect
|
||||
titleDeselect={tracker.string.TaskUnAssign}
|
||||
on:change={() => change('assignee', object.assignee) }
|
||||
/>
|
||||
</Grid>
|
||||
<Panel
|
||||
reverseCommands={true}
|
||||
useOverlay={false}
|
||||
rightSection={rightSection !== undefined}
|
||||
on:close={() => {
|
||||
dispatch('close')
|
||||
}}
|
||||
>
|
||||
<svelte:fragment slot="subtitle">
|
||||
{#if currentTeam}
|
||||
<IssuePresenter value={object} {currentTeam} />
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="actions">
|
||||
<div class="tool flex gap-1">
|
||||
<Button icon={IconDown}/>
|
||||
<Button icon={IconUp}/>
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
<div class="p-10">
|
||||
<Grid column={1} rowGap={1.5}>
|
||||
<EditBox
|
||||
label={tracker.string.Title}
|
||||
bind:value={object.title}
|
||||
placeholder={tracker.string.IssueTitlePlaceholder}
|
||||
maxWidth={'16rem'}
|
||||
focus
|
||||
on:change={() => change('title', object?.title)}
|
||||
/>
|
||||
<StyledTextBox
|
||||
alwaysEdit
|
||||
bind:content={object.description}
|
||||
placeholder={tracker.string.IssueDescriptionPlaceholder}
|
||||
on:value={(evt) => change('description', evt.detail)}
|
||||
/>
|
||||
<UserBox
|
||||
_class={contact.class.Employee}
|
||||
title={tracker.string.Assignee}
|
||||
caption={tracker.string.Assignee}
|
||||
bind:value={object.assignee}
|
||||
allowDeselect
|
||||
titleDeselect={tracker.string.TaskUnAssign}
|
||||
on:change={() => change('assignee', object?.assignee)}
|
||||
/>
|
||||
</Grid>
|
||||
</div>
|
||||
</Panel>
|
||||
{/if}
|
||||
</Card>
|
||||
|
||||
<style lang="scss">
|
||||
.description {
|
||||
display: flex;
|
||||
padding: 1rem;
|
||||
height: 12rem;
|
||||
border-radius: .25rem;
|
||||
border-radius: 0.25rem;
|
||||
background-color: var(--theme-bg-accent-color);
|
||||
border: 1px solid var(--theme-bg-accent-color);
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
<script lang="ts">
|
||||
import { getClient } from '@anticrm/presentation'
|
||||
import type { Issue, Team } from '@anticrm/tracker'
|
||||
import { Icon, showPopup } from '@anticrm/ui'
|
||||
import { Icon, showPanel } from '@anticrm/ui'
|
||||
import tracker from '../../plugin'
|
||||
|
||||
export let value: Issue
|
||||
@ -27,7 +27,7 @@
|
||||
const shortLabel = client.getHierarchy().getClass(value._class).shortLabel
|
||||
|
||||
function show (evt: Event) {
|
||||
showPopup(tracker.component.EditIssue, { object: value }, evt.currentTarget)
|
||||
showPanel(tracker.component.EditIssue, value._id, value._class, 'content')
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -34,6 +34,8 @@
|
||||
export let _id: Ref<Doc>
|
||||
export let _class: Ref<Class<Doc>>
|
||||
export let rightSection: AnyComponent | undefined = undefined
|
||||
export let position: PopupAlignment | undefined = undefined
|
||||
|
||||
let lastId: Ref<Doc> = _id
|
||||
let lastClass: Ref<Class<Doc>> = _class
|
||||
let object: Doc
|
||||
@ -244,6 +246,7 @@
|
||||
{rightSection}
|
||||
{fullSize}
|
||||
{object}
|
||||
{position}
|
||||
on:close={() => {
|
||||
dispatch('close')
|
||||
}}
|
||||
|
@ -21,13 +21,17 @@
|
||||
import { getMetadata, IntlString } from '@anticrm/platform'
|
||||
import { Avatar, createQuery, setClient } from '@anticrm/presentation'
|
||||
import {
|
||||
AnyComponent, closePopup,
|
||||
AnyComponent,
|
||||
closePanel,
|
||||
closePopup,
|
||||
closeTooltip,
|
||||
Component, getCurrentLocation,
|
||||
Component,
|
||||
getCurrentLocation,
|
||||
location,
|
||||
Location,
|
||||
navigate,
|
||||
PanelInstance,
|
||||
panelstore,
|
||||
Popup,
|
||||
showPopup,
|
||||
TooltipInstance
|
||||
@ -43,7 +47,6 @@
|
||||
import NavHeader from './NavHeader.svelte'
|
||||
import Navigator from './Navigator.svelte'
|
||||
import SpaceView from './SpaceView.svelte'
|
||||
|
||||
|
||||
export let client: Client
|
||||
|
||||
@ -91,8 +94,11 @@
|
||||
async function updateSpace (spaceId?: Ref<Space>, spaceSpecial?: string): Promise<void> {
|
||||
if (spaceId === currentSpace) {
|
||||
// Check if we need update location.
|
||||
const loc = getCurrentLocation()
|
||||
if (spaceSpecial !== currentSpecial && spaceSpecial !== asideId) {
|
||||
closePopup()
|
||||
closePanel()
|
||||
closeTooltip()
|
||||
const loc = getCurrentLocation()
|
||||
if (spaceSpecial !== undefined) {
|
||||
setSpaceSpecial(loc, spaceSpecial)
|
||||
} else {
|
||||
@ -120,6 +126,9 @@
|
||||
createItemDialog = currentView?.createItemDialog ?? undefined
|
||||
createItemLabel = currentView?.createItemLabel ?? undefined
|
||||
|
||||
closePopup()
|
||||
closePanel()
|
||||
closeTooltip()
|
||||
const loc = getCurrentLocation()
|
||||
loc.path[2] = spaceId
|
||||
loc.path.length = 3
|
||||
@ -160,6 +169,9 @@
|
||||
loc.path[2] = id
|
||||
loc.path.length = 3
|
||||
navigate(loc)
|
||||
closePopup()
|
||||
closePanel()
|
||||
closeTooltip()
|
||||
}
|
||||
}
|
||||
|
||||
@ -234,6 +246,10 @@
|
||||
createItemDialog = undefined
|
||||
createItemLabel = undefined
|
||||
|
||||
closePanel()
|
||||
closeTooltip()
|
||||
closePopup()
|
||||
|
||||
const loc = getCurrentLocation()
|
||||
loc.path[1] = app._id
|
||||
loc.path.length = 2
|
||||
@ -263,26 +279,34 @@
|
||||
navigate(loc)
|
||||
asideId = undefined
|
||||
}
|
||||
|
||||
let contentPanel: HTMLElement
|
||||
</script>
|
||||
|
||||
{#if client}
|
||||
<svg class="svg-mask">
|
||||
<clipPath id="notify-normal">
|
||||
<path d="M0,0v52.5h52.5V0H0z M34,23.2c-3.2,0-5.8-2.6-5.8-5.8c0-3.2,2.6-5.8,5.8-5.8c3.2,0,5.8,2.6,5.8,5.8 C39.8,20.7,37.2,23.2,34,23.2z" />
|
||||
<path
|
||||
d="M0,0v52.5h52.5V0H0z M34,23.2c-3.2,0-5.8-2.6-5.8-5.8c0-3.2,2.6-5.8,5.8-5.8c3.2,0,5.8,2.6,5.8,5.8 C39.8,20.7,37.2,23.2,34,23.2z"
|
||||
/>
|
||||
</clipPath>
|
||||
<clipPath id="notify-small">
|
||||
<path d="M0,0v45h45V0H0z M29.5,20c-2.8,0-5-2.2-5-5s2.2-5,5-5s5,2.2,5,5S32.3,20,29.5,20z" />
|
||||
</clipPath>
|
||||
<clipPath id="nub-bg">
|
||||
<path d="M7.3.6 4.2 4.3C2.9 5.4 1.5 6 0 6v1h18V6c-1.5 0-2.9-.6-4.2-1.7L10.7.6C9.9-.1 8.5-.2 7.5.4c0 .1-.1.1-.2.2z" />
|
||||
<path
|
||||
d="M7.3.6 4.2 4.3C2.9 5.4 1.5 6 0 6v1h18V6c-1.5 0-2.9-.6-4.2-1.7L10.7.6C9.9-.1 8.5-.2 7.5.4c0 .1-.1.1-.2.2z"
|
||||
/>
|
||||
</clipPath>
|
||||
<clipPath id="nub-border">
|
||||
<path d="M4.8 5.1 8 1.3s.1 0 .1-.1c.5-.3 1.4-.3 1.9.1L13.1 5l.1.1 1.2.9H18c-1.5 0-2.9-.6-4.2-1.7L10.7.6C9.9-.1 8.5-.2 7.5.4c0 .1-.1.1-.2.2L4.2 4.3C2.9 5.4 1.5 6 0 6h3.6l1.2-.9z" />
|
||||
<path
|
||||
d="M4.8 5.1 8 1.3s.1 0 .1-.1c.5-.3 1.4-.3 1.9.1L13.1 5l.1.1 1.2.9H18c-1.5 0-2.9-.6-4.2-1.7L10.7.6C9.9-.1 8.5-.2 7.5.4c0 .1-.1.1-.2.2L4.2 4.3C2.9 5.4 1.5 6 0 6h3.6l1.2-.9z"
|
||||
/>
|
||||
</clipPath>
|
||||
</svg>
|
||||
<div class="workbench-container">
|
||||
<div class="antiPanel-application" on:click={toggleNav}>
|
||||
<div class="flex-col mt-1">
|
||||
<div class="flex-col mt-1">
|
||||
<!-- <ActivityStatus status="active" /> -->
|
||||
<AppItem
|
||||
icon={TopMenu}
|
||||
@ -319,7 +343,8 @@
|
||||
notify={hasNotification}
|
||||
/>
|
||||
<div class="flex-center">
|
||||
<div id="profile-button"
|
||||
<div
|
||||
id="profile-button"
|
||||
class="cursor-pointer"
|
||||
on:click|stopPropagation={(el) => {
|
||||
showPopup(AccountPopup, {}, 'account')
|
||||
@ -334,10 +359,10 @@
|
||||
</div>
|
||||
{#if currentApplication && navigatorModel && navigator && visibileNav}
|
||||
<div class="antiPanel-navigator" style="box-shadow: -1px 0px 2px rgba(0, 0, 0, .1)">
|
||||
{#if currentApplication}
|
||||
{#if currentApplication}
|
||||
<NavHeader label={currentApplication.label} />
|
||||
{#if currentApplication.navHeaderComponent}
|
||||
<Component is={currentApplication.navHeaderComponent} props={{ currentSpace }}/>
|
||||
<Component is={currentApplication.navHeaderComponent} props={{ currentSpace }} />
|
||||
{/if}
|
||||
{/if}
|
||||
<Navigator
|
||||
@ -349,24 +374,29 @@
|
||||
on:archive={(evt) => selectArchive()}
|
||||
/>
|
||||
{#if currentApplication.navFooterComponent}
|
||||
<Component is={currentApplication.navFooterComponent} props={{ currentSpace }}/>
|
||||
<Component is={currentApplication.navFooterComponent} props={{ currentSpace }} />
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
<div class="antiPanel-component antiComponent border-left">
|
||||
<div class="antiPanel-component antiComponent border-left" bind:this={contentPanel}>
|
||||
{#if currentApplication && currentApplication.component}
|
||||
<Component is={currentApplication.component} props={{ currentSpace }}/>
|
||||
<Component is={currentApplication.component} props={{ currentSpace }} />
|
||||
{:else if specialComponent}
|
||||
<Component is={specialComponent.component} props={{ model: navigatorModel, ...specialComponent.componentProps, currentSpace }} />
|
||||
<Component
|
||||
is={specialComponent.component}
|
||||
props={{ model: navigatorModel, ...specialComponent.componentProps, currentSpace }}
|
||||
/>
|
||||
{:else}
|
||||
<SpaceView {currentSpace} {currentView} {createItemDialog} {createItemLabel} />
|
||||
{/if}
|
||||
</div>
|
||||
{#if asideId && navigatorModel?.aside !== undefined}
|
||||
<div class="antiPanel-component indent antiComponent filled"><Component is={navigatorModel.aside} props={{ currentSpace, _id: asideId }} on:close={closeAside} /></div>
|
||||
<div class="antiPanel-component indent antiComponent filled">
|
||||
<Component is={navigatorModel.aside} props={{ currentSpace, _id: asideId }} on:close={closeAside} />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<PanelInstance />
|
||||
<PanelInstance {contentPanel} />
|
||||
<Popup />
|
||||
<TooltipInstance />
|
||||
{:else}
|
||||
|
Loading…
Reference in New Issue
Block a user