platform/plugins/workbench-resources/src/components/EditStatuses.svelte
Alexander Platov 4717598936
Fix colors in dialogs (#306)
Signed-off-by: Alexander Platov <sas_lord@mail.ru>
2021-11-16 17:13:07 +01:00

231 lines
6.9 KiB
Svelte

<!--
// Copyright © 2020, 2021 Anticrm Platform Contributors.
// Copyright © 2021 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 { Ref, SpaceWithStates, State, Class, Obj } from '@anticrm/core'
import { CircleButton, IconAdd, Label, IconMoreH, ActionIcon, showPopup, ScrollBox } from '@anticrm/ui'
import { createQuery, getClient, AttributeEditor } from '@anticrm/presentation'
import type { Kanban } from '@anticrm/view'
import { createEventDispatcher } from 'svelte'
import Close from './icons/Close.svelte'
import Circles from './icons/Circles.svelte'
import Status from './icons/Status.svelte'
import ColorsPopup from './ColorsPopup.svelte'
import StatusesPopup from './StatusesPopup.svelte'
import core from '@anticrm/core'
import view from '@anticrm/view'
export let _id: Ref<SpaceWithStates>
export let spaceClass: Ref<Class<Obj>>
let kanban: Kanban | undefined
let states: State[] = []
let elements: HTMLElement[] = []
const client = getClient()
function sort(states: State[]): State[] {
if (kanban === undefined || states.length === 0) { return [] }
console.log(states)
const map = states.reduce((map, state) => { map.set(state._id, state); return map }, new Map<Ref<State>, State>())
console.log(kanban.states)
const x = kanban.states.map(id => map.get(id) as State )
return x
}
const kanbanQuery = createQuery()
$: kanbanQuery.query(view.class.Kanban, { attachedTo: _id }, result => { kanban = result[0] })
const query = createQuery()
$: query.query(core.class.State, { _id: { $in: kanban?.states ?? [] } }, result => { states = sort(result) })
let selected: number | undefined
let dragState: Ref<State>
let dragStateInitialPosition: number
function dragswap(ev: MouseEvent, i: number): boolean {
let s = selected as number
if (i < s) {
return ev.offsetY < elements[i].offsetHeight / 2
} else if (i > s) {
return ev.offsetY > elements[i].offsetHeight / 2
}
return false
}
function dragover(ev: MouseEvent, i: number) {
let s = selected as number
if (dragswap(ev, i)) {
const dragover = states[i]
const dragging = states[s]
states[i] = dragging
states[s] = dragover
selected = i
}
}
async function move(to: number) {
client.updateDoc(view.class.Kanban, _id, (kanban as Kanban)._id, {
$move: {
states: {
$value: dragState,
$position: to
}
}
})
}
const dispatch = createEventDispatcher()
async function addStatus () {
const state = await client.createDoc(core.class.State, _id, {
title: 'New State',
color: '#7C6FCD'
})
await client.updateDoc(view.class.Kanban, _id, (kanban as Kanban)._id, {
$push: {
states: state
}
})
}
</script>
<div class="flex-col floatdialog-container">
<div class="flex-between header">
<div class="flex-grow flex-col">
<div class="flex-row-center">
<div class="icon"><Status size={'small'} /></div>
<span class="overflow-label title">Manage application statuses within vacancy</span>
</div>
<div class="overflow-label subtitle">Vacancy name</div>
</div>
<div class="tool" on:click={() => dispatch('close')}><Close size={'small'} /></div>
</div>
<div class="flex-grow flex-col content">
<div class="flex-no-shrink flex-between states-header">
<Label label={'ACTIVE STATUSES'} />
<div on:click={addStatus}><CircleButton icon={IconAdd} size={'medium'} /></div>
</div>
<div class="vScroll"><div class="h-full">
{#each states as state, i}
{#if state}
<div bind:this={elements[i]} class="flex-between states" draggable={true}
on:dragover|preventDefault={(ev) => {
dragover(ev, i)
}}
on:drop|preventDefault={() => {
move(i)
}}
on:dragstart={() => {
dragStateInitialPosition = selected = i
dragState = states[i]._id
}}
on:dragend={() => {
selected = undefined
}}
>
<div class="bar"><Circles /></div>
<div class="color" style="background-color: {state.color}"
on:click={() => {
showPopup(ColorsPopup, {}, elements[i], (result) => { if (result) state.color = result })
}}
/>
<div class="flex-grow caption-color"><AttributeEditor maxWidth="20rem" _class={core.class.State} object={state} key="title"/></div>
<div class="tool hover-trans"
on:click={(ev) => {
showPopup(StatusesPopup, { kanban, state, spaceClass }, ev.target, (result) => { if (result) console.log('StatusesPopup:', result) })
}}
>
<IconMoreH size={'medium'} />
</div>
</div>
{/if}
{/each}
</div></div>
</div>
</div>
<style lang="scss">
.floatdialog-container {
margin: 2rem 1rem 1.25rem 0;
height: calc(100% - 3.25rem);
background: var(--theme-dialog-bg-spec);
border-radius: 1.25rem;
box-shadow: var(--theme-dialog-shadow);
backdrop-filter: blur(15px);
.header {
padding: 0 2rem 0 2.5rem;
height: 4.5rem;
min-height: 4.5rem;
.icon {
margin-right: .5rem;
opacity: .6;
}
.title {
font-weight: 500;
font-size: 1rem;
color: var(--theme-caption-color);
}
.subtitle {
font-size: .75rem;
color: var(--theme-content-dark-color);
}
.tool {
margin-left: 2.5rem;
cursor: pointer;
}
}
.content { margin: 1rem 2.5rem 1rem 2.5rem; }
}
.states {
padding: .625rem 1rem;
color: #fff;
background-color: rgba(67, 67, 72, .3);
border: 1px solid var(--theme-bg-accent-color);
border-radius: .75rem;
user-select: none;
&-header {
margin-bottom: 1rem;
font-weight: 600;
font-size: .75rem;
color: var(--theme-content-trans-color);
}
.bar {
margin-right: .375rem;
width: .375rem;
height: 1rem;
opacity: .4;
cursor: grabbing;
}
.color {
margin-right: .75rem;
width: 1rem;
height: 1rem;
border-radius: .25rem;
cursor: pointer;
}
.tool { margin-left: 1rem; }
}
.states + .states { margin-top: .5rem; }
</style>