Board: Add card labels picker popup (#1434)

Signed-off-by: Anna No <anna.no@xored.com>
This commit is contained in:
Anna No
2022-04-18 17:27:29 +07:00
committed by GitHub
parent ffa04233fe
commit 9342d5a5fe
14 changed files with 159 additions and 20 deletions
+5 -1
View File
@@ -136,7 +136,7 @@ p:last-child { margin-block-end: 0; }
flex-wrap: nowrap;
min-width: 0;
}
.flex-row-streach {
.flex-row-stretch {
display: flex;
align-items: stretch;
flex-wrap: nowrap;
@@ -171,6 +171,7 @@ p:last-child { margin-block-end: 0; }
}
.justify-between { justify-content: space-between; }
.justify-end { justify-content: flex-end; }
.justify-center { justify-content: center; }
.items-baseline { align-items: baseline; }
.flex-gap-3 {gap: .75rem;}
@@ -345,6 +346,7 @@ p:last-child { margin-block-end: 0; }
/* --------- */
.no-word-wrap { word-wrap: none; }
.relative { position: relative; }
.absolute { position: absolute; }
.abs-lt-content {
position: absolute;
top: var(--modal-padding);
@@ -381,10 +383,12 @@ p:last-child { margin-block-end: 0; }
.h-full { height: 100%; }
.h-2 { height: .5rem; }
.h-8 { height: 2rem; }
.h-9 { height: 2.25rem; }
.h-16 { height: 4rem; }
.h-18 { height: 4.5rem; }
.w-full { width: 100%; }
.w-2 { width: .5rem; }
.w-9 { width: 2.25rem; }
.w-85 {width: 21.25rem; }
.w-165 {width: 41.25rem; }
+12
View File
@@ -74,3 +74,15 @@ export function hexColorToNumber (hexColor: string): number {
export function numberToHexColor (color: number): string {
return `#${color.toString(16)}`
}
/**
* @public
*/
export function numberToRGB (color: number, alpha?: number): string {
const hex = color.toString(16)
const r = parseInt(hex.slice(0, 2), 16)
const g = parseInt(hex.slice(2, 4), 16)
const b = parseInt(hex.slice(4, 6), 16)
return `rgba(${r}, ${g}, ${b}, ${alpha === undefined ? '1' : alpha})`
}
+2
View File
@@ -30,6 +30,8 @@
"Suggested": "Suggested",
"AddToCard": "Add to card",
"Labels": "Labels",
"CreateLabel": "Create a new label",
"SearchLabels": "Search labels...",
"Checklist": "Checklist",
"Dates": "Dates",
"Attachments": "Attachments",
+2
View File
@@ -30,6 +30,8 @@
"Suggested": "Предложенное",
"AddToCard": "Добавить",
"Labels": "Метки",
"CreateLabel": "Создать",
"SearchLabels": "Поиск...",
"Checklist": "Списки",
"Dates": "Дата",
"Attachments": "Прикрепленное",
@@ -78,7 +78,7 @@
<Scroller>
<div class="flex-col-stretch h-full w-165 p-6">
<!-- TODO cover -->
<div class="flex-row-streach">
<div class="flex-row-stretch">
<div class="w-9">
<Icon icon={board.icon.Card} size="large" />
</div>
@@ -91,20 +91,20 @@
/>
</div>
</div>
<div class="flex-row-streach">
<div class="flex-row-stretch">
<div class="w-9" />
<div>
<Label label={board.string.InList} />
<span class="state-name ml-1" on:click={handleMove}>{state?.title}</span>
</div>
</div>
<div class="flex-row-streach">
<div class="flex-row-stretch">
<div class="flex-grow mr-4">
<div class="flex-row-streach">
<div class="flex-row-stretch">
<div class="w-9" />
<CardDetails bind:value={object} />
</div>
<div class="flex-row-streach mt-4 mb-2">
<div class="flex-row-stretch mt-4 mb-2">
<div class="w-9">
<Icon icon={board.icon.Card} size="large" />
</div>
@@ -112,7 +112,7 @@
<Label label={board.string.Description} />
</div>
</div>
<div class="flex-row-streach">
<div class="flex-row-stretch">
<div class="w-9" />
<div class="background-bg-accent border-bg-accent border-radius-3 p-2 w-full">
<StyledTextBox
@@ -26,7 +26,7 @@
{#if value !== undefined}
<div class="flex-col-stretch h-full w-full">
<div class="flex-row-streach mt-4 mb-2">
<div class="flex-row-stretch mt-4 mb-2">
<div class="w-9">
<Icon icon={IconActivity} size="large" />
</div>
@@ -42,7 +42,7 @@
}}
/>
</div>
<div class="flex-row-streach">
<div class="flex-row-stretch">
<div class="w-9" />
<div class="w-full">
<Component is={chunter.component.CommentInput} props={{ object: value }} />
@@ -38,7 +38,7 @@
{#if value !== undefined && value.attachments !== undefined && value.attachments > 0}
<div class="flex-col w-full">
<div class="flex-row-streach mt-4 mb-2">
<div class="flex-row-stretch mt-4 mb-2">
<div class="w-9">
<Icon icon={IconAttachment} size="large" />
</div>
@@ -46,7 +46,7 @@
<Label label={board.string.Attachments} />
</div>
</div>
<div class="flex-row-streach">
<div class="flex-row-stretch">
<div class="w-9" />
<div class="flex-col flex-gap-1 w-full">
{#each attachments as attach}
@@ -37,17 +37,21 @@
let labelsHandler: () => void
let dateHandler: () => void
$: value.members &&
value.members.length > 0 &&
$: if (value.members && value.members.length > 0) {
query.query(contact.class.Employee, { _id: { $in: value.members } }, (result) => {
members = result
})
} else {
members = []
}
$: value.labels &&
value.labels.length > 0 &&
$: if (value.labels && value.labels.length > 0) {
query.query(board.class.CardLabel, { _id: { $in: value.labels } }, (result) => {
labels = result
})
} else {
labels = []
}
getCardActions(client, {
_id: { $in: [board.cardAction.Dates, board.cardAction.Labels, board.cardAction.Members] }
@@ -65,6 +69,7 @@
}
}
})
</script>
{#if value}
@@ -82,7 +87,7 @@
</div>
{/if}
{#if labels && labels.length > 0}
<div class="flex-col mt-4 mr6">
<div class="flex-col mt-4 mr-6">
<div class="text-md font-medium">
<Label label={board.string.Labels} />
</div>
@@ -0,0 +1,105 @@
<script lang="ts">
import { Card, CardLabel } from '@anticrm/board'
import { Ref } from '@anticrm/core'
import { getClient } from '@anticrm/presentation'
import { Button, EditBox, Icon, IconEdit, IconCheck, Label, numberToHexColor, numberToRGB } from '@anticrm/ui'
import board from '../../plugin'
import { getBoardLabels } from '../../utils/BoardUtils'
import { updateCard } from '../../utils/CardUtils'
export let object: Card
const client = getClient()
let search: string | undefined = undefined
let labels = object.labels ?? []
let boardCardLabels: CardLabel[] = []
let filteredLabels: CardLabel[] = []
let hovered: Ref<CardLabel> | undefined = undefined
function applySearch() {
if (!search || search.trim().length <= 0) {
filteredLabels = boardCardLabels
return
}
const text = search!.toUpperCase()
filteredLabels = boardCardLabels.filter((l) => l.title?.toUpperCase().includes(text) ?? false)
}
async function fetchBoardLabels() {
if (object.space) {
boardCardLabels = await getBoardLabels(client, object.space)
applySearch()
}
}
function toggle(label: CardLabel) {
if (!object) {
return
}
if (labels.includes(label._id)) {
labels = labels.filter((l) => l !== label._id)
} else {
labels = [...labels, label._id]
}
updateCard(client, object, 'labels', labels)
}
$: object.space && fetchBoardLabels()
</script>
<div class="antiPopup antiPopup-withHeader antiPopup-withTitle w-85 pb-2">
<div class="ap-space" />
<div class="fs-title ap-header flex-row-center">
<Label label={board.string.Labels} />
</div>
<div class="ap-space bottom-divider" />
<div class="flex-col ml-4 mt-1 mb-1 mr-2 flex-gap-1">
<div class="p-2 mt-1 mb-1 border-bg-accent border-radius-1">
<EditBox
bind:value={search}
maxWidth="100%"
placeholder={board.string.SearchLabels}
on:change={() => applySearch()} />
</div>
<div class="text-md font-medium">
<Label label={board.string.Labels} />
</div>
{#each filteredLabels as label}
<div
class="flex-row-stretch"
on:mouseover={() => {
hovered = label._id
}}
on:focus={() => {
hovered = label._id
}}
on:mouseout={() => {
hovered = undefined
}}
on:blur={() => {
hovered = undefined
}}>
<div
class="relative flex-row-center justify-center border-radius-1 fs-title w-full h-8 mr-2"
style:background-color={numberToHexColor(label.color)}
style:box-shadow={hovered === label._id ? `-0.5rem 0 ${numberToRGB(label.color, 0.6)}` : ''}
on:click={() => toggle(label)}>
{label.title ?? ''}
{#if labels.includes(label._id)}
<div class="absolute flex-center h-full mr-2" style:top="0" style:right="0">
<Icon icon={IconCheck} size="small" />
</div>
{/if}
</div>
<Button icon={IconEdit} kind="transparent" />
</div>
{/each}
<div class="mt-3" />
<Button label={board.string.CreateLabel} kind="no-border" />
</div>
</div>
+8 -1
View File
@@ -25,6 +25,7 @@ import EditCard from './components/EditCard.svelte'
import KanbanCard from './components/KanbanCard.svelte'
import TemplatesIcon from './components/TemplatesIcon.svelte'
import KanbanView from './components/KanbanView.svelte'
import CardLabelsPicker from './components/popups/CardLabelsPicker.svelte'
import MoveView from './components/popups/MoveCard.svelte'
import DateRangePicker from './components/popups/DateRangePicker.svelte'
import { addCurrentUser, canAddCurrentUser, isArchived, isUnarchived } from './utils/CardUtils'
@@ -36,6 +37,11 @@ async function showMoveCardPopup (object: Card): Promise<void> {
async function showDatePickerPopup (object: Card): Promise<void> {
showPopup(DateRangePicker, { object })
}
async function showCardLabelsPopup (object: Card): Promise<void> {
showPopup(CardLabelsPicker, { object })
}
export default async (): Promise<Resources> => ({
component: {
CreateBoard,
@@ -50,7 +56,8 @@ export default async (): Promise<Resources> => ({
cardActionHandler: {
Join: addCurrentUser,
Move: showMoveCardPopup,
Dates: showDatePickerPopup
Dates: showDatePickerPopup,
Labels: showCardLabelsPopup
},
cardActionSupportedHandler: {
Join: canAddCurrentUser,
+2
View File
@@ -51,6 +51,8 @@ export default mergeIds(boardId, board, {
Suggested: '' as IntlString,
AddToCard: '' as IntlString,
Labels: '' as IntlString,
CreateLabel: '' as IntlString,
SearchLabels: '' as IntlString,
Checklist: '' as IntlString,
Dates: '' as IntlString,
Attachments: '' as IntlString,
@@ -92,7 +92,7 @@
</script>
{#if object !== undefined}
<div class="flex-row-streach flex-grow">
<div class="flex-row-stretch flex-grow">
<div class="mr-8">
{#if editable}
<EditableAvatar avatar={object.avatar} size={'x-large'} on:done={onAvatarDone} on:remove={removeAvatar} />
@@ -110,7 +110,7 @@
<div class="ac-header__icon"><Icon icon={notification.icon.Notifications} size={'medium'} /></div>
<div class="ac-header__title"><Label label={notification.string.Notifications}/></div>
</div>
<div class="flex-row-streach flex-grow container">
<div class="flex-row-stretch flex-grow container">
<div class="flex-col flex-grow">
<div class="flex-grow">
<Grid {column} columnGap={5} rowGap={1.5} >
@@ -46,7 +46,7 @@
<div class="ac-header__icon"><Icon icon={setting.icon.Password} size={'medium'} /></div>
<div class="ac-header__title"><Label label={setting.string.ChangePassword} /></div>
</div>
<div class="flex-row-streach flex-grow p-10">
<div class="flex-row-stretch flex-grow p-10">
<div class="flex-grow flex-col">
<div class="flex-grow flex-col">
<div>