mirror of
https://github.com/hcengineering/platform.git
synced 2024-11-23 05:53:09 +03:00
Update StatesBar layout. Fix StyledTextBox. (#994)
Signed-off-by: Alexander Platov <sas_lord@mail.ru>
This commit is contained in:
parent
8505d9f9ba
commit
aca81cedb0
@ -86,6 +86,7 @@
|
||||
flex-grow: 1;
|
||||
}
|
||||
.text {
|
||||
overflow: auto;
|
||||
flex-grow: 1;
|
||||
line-height: 150%;
|
||||
}
|
||||
|
@ -368,6 +368,7 @@ a.no-line {
|
||||
&:visited { color: var(--theme-caption-color); }
|
||||
}
|
||||
.cursor-pointer { cursor: pointer; }
|
||||
.cursor-default { cursor: default; }
|
||||
|
||||
/* Text */
|
||||
.text-sm { font-size: .75rem; }
|
||||
@ -400,6 +401,7 @@ a.no-line {
|
||||
visibility: hidden;
|
||||
overflow: hidden;
|
||||
white-space: pre-wrap;
|
||||
width: max-content;
|
||||
}
|
||||
.overflow-label {
|
||||
white-space: nowrap;
|
||||
|
@ -27,10 +27,10 @@
|
||||
<div class="bar" style="background-color: {color}" />
|
||||
<div class="flex-between label">
|
||||
<div>
|
||||
{label}
|
||||
<span class="lines-limit-2">{label}</span>
|
||||
<!-- <span>({counter})</span> -->
|
||||
</div>
|
||||
<div class="tool" on:click|preventDefault={addAction}>
|
||||
<div class="tool ml-3" on:click|preventDefault={addAction}>
|
||||
<IconAdd size={'small'} />
|
||||
</div>
|
||||
</div>
|
||||
|
@ -13,22 +13,27 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import { Ref, SortingOrder } from '@anticrm/core'
|
||||
import { createQuery } from '@anticrm/presentation'
|
||||
import task, { SpaceWithStates, State } from '@anticrm/task'
|
||||
import { getPlatformColor } from '@anticrm/ui'
|
||||
import { createEventDispatcher, onDestroy, onMount } from 'svelte'
|
||||
import { createEventDispatcher, onDestroy, onMount, afterUpdate } from 'svelte'
|
||||
import StatesBarElement from './StatesBarElement.svelte'
|
||||
import type { StatesBarPosition } from '../..'
|
||||
|
||||
export let space: Ref<SpaceWithStates>
|
||||
export let state: Ref<State> | undefined = undefined
|
||||
export let gap: 'small' | 'big' = 'small'
|
||||
|
||||
let states: State[] = []
|
||||
|
||||
let div: HTMLElement
|
||||
let maskLeft: boolean = false
|
||||
let maskRight: boolean = false
|
||||
let mask: 'left' | 'right' | 'both' | 'none' = 'none'
|
||||
let stepStyle = (gap === 'small') ? 'step-lr25' : 'step-lr75'
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
@ -58,7 +63,9 @@
|
||||
|
||||
const selectItem = (ev: Event, item: State): void => {
|
||||
const el: HTMLElement = ev.currentTarget as HTMLElement
|
||||
el.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'center' })
|
||||
const rect = el.getBoundingClientRect()
|
||||
const rectScroll = div.getBoundingClientRect()
|
||||
div.scrollBy({ top: 0, left: rect.left + (rect.width / 2) - (rectScroll.left + rectScroll.width / 2), behavior: 'smooth' })
|
||||
if (state === item._id) {
|
||||
state = undefined
|
||||
} else {
|
||||
@ -67,40 +74,32 @@
|
||||
dispatch('change')
|
||||
}
|
||||
|
||||
const getPosition = (n: number): StatesBarPosition => {
|
||||
if (n === 0) return 'start'
|
||||
else if (n === states.length - 1) return 'end'
|
||||
else return 'middle'
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
if (div) {
|
||||
checkMask()
|
||||
div.addEventListener('scroll', checkMask)
|
||||
}
|
||||
})
|
||||
onDestroy(() => {
|
||||
if (div) div.removeEventListener('scroll', checkMask)
|
||||
})
|
||||
onDestroy(() => { if (div) div.removeEventListener('scroll', checkMask) })
|
||||
</script>
|
||||
|
||||
<div bind:this={div} class="flex-row-center statusesbar-container {mask}">
|
||||
{#each states as item, i}
|
||||
<div
|
||||
class="flex-row-center cursor-pointer step-lr25"
|
||||
class:selected={item._id === state}
|
||||
<div bind:this={div} class="flex-row-center statusesbar-container mask-{mask} {stepStyle}">
|
||||
{#each states as item, i (item._id)}
|
||||
<StatesBarElement
|
||||
label={item.title}
|
||||
position={getPosition(i)}
|
||||
selected={item._id === state}
|
||||
color={getPlatformColor(item.color)}
|
||||
on:click={(ev) => {
|
||||
selectItem(ev, item)
|
||||
if (item._id !== state) selectItem(ev, item)
|
||||
}}
|
||||
>
|
||||
<StatesBarElement side={'left'} kind={i ? 'arrow' : 'round'} selected={item._id === state} color={getPlatformColor(item.color)} />
|
||||
<div
|
||||
class="flex-row-center overflow-label label"
|
||||
style={item._id === state ? `background-color: ${getPlatformColor(item.color)};` : ''}
|
||||
>
|
||||
{item.title}
|
||||
</div>
|
||||
<StatesBarElement
|
||||
side={'right'}
|
||||
kind={i < states.length - 1 ? 'arrow' : 'round'}
|
||||
selected={item._id === state}
|
||||
color={getPlatformColor(item.color)}
|
||||
/>
|
||||
</div>
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
@ -108,6 +107,7 @@
|
||||
.statusesbar-container {
|
||||
overflow-x: auto;
|
||||
padding: 0.125rem 0;
|
||||
width: auto;
|
||||
|
||||
&::-webkit-scrollbar:horizontal {
|
||||
height: 0.125rem;
|
||||
@ -120,28 +120,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
.label {
|
||||
// padding: 0.5rem 2rem;
|
||||
height: 2.25rem;
|
||||
max-height: 2.25rem;
|
||||
color: var(--theme-caption-color);
|
||||
background-color: var(--theme-button-bg-enabled);
|
||||
border-top: 1px solid var(--theme-button-border-enabled);
|
||||
border-bottom: 1px solid var(--theme-button-border-enabled);
|
||||
}
|
||||
|
||||
.selected {
|
||||
.label {
|
||||
border-color: transparent;
|
||||
}
|
||||
}
|
||||
.left {
|
||||
.mask-left {
|
||||
mask-image: linear-gradient(to right, rgba(0, 0, 0, 0) 0, rgba(0, 0, 0, 1) 1rem);
|
||||
}
|
||||
.right {
|
||||
.mask-right {
|
||||
mask-image: linear-gradient(to left, rgba(0, 0, 0, 0) 0, rgba(0, 0, 0, 1) 1rem);
|
||||
}
|
||||
.both {
|
||||
.mask-both {
|
||||
mask-image: linear-gradient(
|
||||
to right,
|
||||
rgba(0, 0, 0, 0) 0,
|
||||
@ -150,7 +135,7 @@
|
||||
rgba(0, 0, 0, 0) 100%
|
||||
);
|
||||
}
|
||||
.none {
|
||||
.mask-none {
|
||||
mask-image: linear-gradient(to right, rgba(0, 0, 0, 0) 1);
|
||||
}
|
||||
</style>
|
||||
|
@ -1,71 +1,103 @@
|
||||
<!--
|
||||
// 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">
|
||||
export let side: 'left' | 'right'
|
||||
export let kind: 'round' | 'arrow'
|
||||
import { afterUpdate } from 'svelte'
|
||||
import type { StatesBarPosition } from '../..'
|
||||
|
||||
export let label: string
|
||||
export let position: StatesBarPosition = undefined
|
||||
export let selected: boolean = false
|
||||
export let color: string
|
||||
export let color: string = 'var(--theme-button-bg-enabled)'
|
||||
|
||||
let lenght: number = 0
|
||||
let text: HTMLElement
|
||||
|
||||
afterUpdate(() => {
|
||||
if (text) lenght = (text.clientWidth + 20 > 300) ? 300 : text.clientWidth + 20
|
||||
})
|
||||
</script>
|
||||
|
||||
<svg class="svg-statesbar-element" viewBox="0 0 8 36" class:selected xmlns="http://www.w3.org/2000/svg">
|
||||
{#if side === 'left' && kind === 'arrow'}
|
||||
<path
|
||||
class="bg"
|
||||
style={selected ? `fill: ${color}` : ''}
|
||||
d="M1,0C0.3,0-0.2,0.7,0.1,1.4l6,15.9c0.2,0.5,0.2,1,0,1.4l-6,15.9C-0.2,35.3,0.3,36,1,36h7V0H1z"
|
||||
/>
|
||||
<path
|
||||
class="border"
|
||||
d="M1,35l6-15.9c0.3-0.7,0.3-1.4,0-2.1L1,1h7V0H1C0.7,0,0.4,0.2,0.2,0.4C0,0.7-0.1,1,0.1,1.4 l6,15.9c0.2,0.5,0.2,1,0,1.4l-6,15.9C-0.1,35,0,35.3,0.2,35.6S0.7,36,1,36h7v-1H1z"
|
||||
/>
|
||||
{:else if side === 'left' && kind === 'round'}
|
||||
<path class="bg" style={selected ? `fill: ${color}` : ''} d="M0,8v10v10c0,4.4,3.6,8,8,8V0C3.6,0,0,3.6,0,8z" />
|
||||
<path class="border" d="M1,28V8c0-3.9,3.1-7,7-7V0C3.6,0,0,3.6,0,8v20c0,4.4,3.6,8,8,8v-1C4.1,35,1,31.9,1,28z" />
|
||||
{:else if side === 'right' && kind === 'arrow'}
|
||||
<path
|
||||
class="bg"
|
||||
style={selected ? `fill: ${color}` : ''}
|
||||
d="M1.8,1.3C1.5,0.5,0.8,0,0,0v36c0.8,0,1.5-0.5,1.8-1.3l6.1-16c0.2-0.5,0.2-1,0-1.4L1.8,1.3z"
|
||||
/>
|
||||
<path
|
||||
class="border"
|
||||
d="M1.8,1.3L1.8,1.3L1.8,1.3c0,0-0.1-0.2-0.1-0.3L1.6,0.8C1.2,0.3,0.6,0,0,0v1 c0.4,0,0.7,0.3,0.9,0.6l6.1,16c0.1,0.2,0.1,0.5,0,0.7l-6.1,16C0.7,34.7,0.4,35,0,35v1c0.8,0,1.5-0.5,1.8-1.3l6.1-16 c0.2-0.5,0.2-1,0-1.4L1.8,1.3z"
|
||||
/>
|
||||
{:else if side === 'right' && kind === 'round'}
|
||||
<path class="bg" style={selected ? `fill: ${color}` : ''} d="M0,0v36c4.4,0,8-3.6,8-8V8C8,3.6,4.4,0,0,0z" />
|
||||
<path class="border" d="M0,0v1c3.9,0,7,3.1,7,7v20c0,3.9-3.1,7-7,7v1c4.4,0,8-3.6,8-8V8C8,3.6,4.4,0,0,0z" />
|
||||
{:else}
|
||||
<rect x={0} y={0} width={'100%'} height={'100%'} fill={'red'} opacity={0.5} />
|
||||
{/if}
|
||||
</svg>
|
||||
<div class="hidden-text" bind:this={text}>{label}</div>
|
||||
{#if lenght > 0}
|
||||
<div
|
||||
class="statuses-bar"
|
||||
class:cursor-pointer={!selected}
|
||||
class:cursor-default={selected}
|
||||
on:click|stopPropagation
|
||||
>
|
||||
<div class="label-container"><div class="overflow-label">{label}</div></div>
|
||||
<svg class="statuses-bar__back" viewBox="0 0 {lenght + 20} 36" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
{#if position === 'start'}
|
||||
<path
|
||||
class="statuses-bar__{selected ? 'selected' : 'element'}"
|
||||
style={selected ? `fill: ${color};` : ''}
|
||||
d="M0,8c0-4.4,3.6-8,8-8h2h{lenght}h1.8c0.8,0,1.6,0.5,1.9,1.3l6.1,16c0.2,0.5,0.2,1,0,1.4l-6.1,16c-0.3,0.8-1,1.3-1.9,1.3L{lenght + 10},36H10 l-2,0c-4.4,0-8-3.6-8-8V8z"
|
||||
/>
|
||||
{:else if position === 'middle'}
|
||||
<path
|
||||
class="statuses-bar__{selected ? 'selected' : 'element'}"
|
||||
style={selected ? `fill: ${color};` : ''}
|
||||
d="M6.1,17.3l-6-15.9C-0.2,0.7,0.3,0,1,0h9h{lenght}h1.8c0.8,0,1.6,0.5,1.9,1.3l6.1,16c0.2,0.5,0.2,1,0,1.4l-6.1,16 c-0.3,0.8-1,1.3-1.9,1.3H{lenght + 10}H10H1c-0.7,0-1.2-0.7-0.9-1.4l6-15.9C6.3,18.3,6.3,17.7,6.1,17.3z"
|
||||
/>
|
||||
{:else if position === 'end'}
|
||||
<path
|
||||
class="statuses-bar__{selected ? 'selected' : 'element'}"
|
||||
style={selected ? `fill: ${color};` : ''}
|
||||
d="M6.1,17.3l-6-15.9C-0.2,0.7,0.3,0,1,0h9h{lenght}h2c4.4,0,8,3.6,8,8v20c0,4.4-3.6,8-8,8h-2H10H1 c-0.7,0-1.2-0.7-0.9-1.4l6-15.9C6.3,18.3,6.3,17.7,6.1,17.3z"
|
||||
/>
|
||||
{:else}
|
||||
<path
|
||||
class="statuses-bar__{selected ? 'selected' : 'element'}"
|
||||
style={selected ? `fill: ${color};` : ''}
|
||||
d="M0,8c0-4.4,3.6-8,8-8l2,0h{lenght}l2,0c4.4,0,8,3.6,8,8v20c0,4.4-3.6,8-8,8h-2H10H8c-4.4,0-8-3.6-8-8V8z"
|
||||
/>
|
||||
{/if}
|
||||
</svg>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style lang="scss">
|
||||
.svg-statesbar-element {
|
||||
width: .5rem;
|
||||
height: 2.25rem;
|
||||
}
|
||||
.bg {
|
||||
fill: var(--theme-button-bg-enabled);
|
||||
}
|
||||
.border {
|
||||
fill: var(--theme-button-border-enabled);
|
||||
}
|
||||
.selected {
|
||||
.border {
|
||||
fill: transparent;
|
||||
.statuses-bar {
|
||||
position: relative;
|
||||
max-width: 100%;
|
||||
height: min-content;
|
||||
|
||||
&__back {
|
||||
height: 2.25rem;
|
||||
}
|
||||
&__element {
|
||||
fill: var(--theme-button-bg-enabled);
|
||||
stroke: var(--theme-bg-accent-color);
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
&__selected { fill: red; }
|
||||
|
||||
.label-container {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
top: 0;
|
||||
left: 1rem;
|
||||
right: 1rem;
|
||||
min-width: 0;
|
||||
width: calc(100% - 2rem);
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -124,6 +124,8 @@ export async function queryTask<D extends Task> (_class: Ref<Class<D>>, client:
|
||||
}))
|
||||
}
|
||||
|
||||
export type StatesBarPosition = 'start' | 'middle' | 'end' | undefined
|
||||
|
||||
export default async (): Promise<Resources> => ({
|
||||
component: {
|
||||
CreateTask,
|
||||
|
Loading…
Reference in New Issue
Block a user