diff --git a/packages/theme/styles/_layouts.scss b/packages/theme/styles/_layouts.scss index 9e8b21f01b..ad00b63991 100644 --- a/packages/theme/styles/_layouts.scss +++ b/packages/theme/styles/_layouts.scss @@ -194,6 +194,7 @@ input.search { .justify-end { justify-content: flex-end; } .justify-center { justify-content: center; } .items-baseline { align-items: baseline; } +.items-center { align-items: center; } .flex-gap-3 { gap: .75rem; } .flex-gap-2 { gap: .5rem; } @@ -456,6 +457,7 @@ input.search { .min-w-80 { min-width: 20rem; } .min-w-min { min-width: min-content; } .min-h-0 { min-height: 0; } +.min-h-7 { min-height: 1.75rem; } .max-h-125 { max-height: 31.25rem; } .max-h-60 { max-height: 15rem; } .max-w-60 { max-width: 15rem; } @@ -540,6 +542,7 @@ a.no-line { .text-lg { font-size: 1.125rem; } .font-normal { font-weight: 400; } .font-medium { font-weight: 500; } +.font-semi-bold { font-weight: 600; } .fs-bold { font-weight: 500; } .uppercase { text-transform: uppercase; } .text-left { text-align: left; } @@ -549,6 +552,8 @@ a.no-line { &:hover { text-decoration: underline; } } +.text-line-through { text-decoration: line-through; } + .hidden-text { position: absolute; visibility: hidden; @@ -632,6 +637,7 @@ a.no-line { .background-highlight-red { background-color: var(--highlight-red); } .background-button-bg-color { background-color: var(--button-bg-color); } .background-button-bg-enabled { background-color: var(--theme-button-bg-enabled); } +.background-button-noborder-bg-hover { background-color: var(--noborder-bg-hover); } .background-menu-divider { background-color: var(--theme-menu-divider); } .background-card-divider { background-color: var(--theme-card-divider); } .background-primary-color { background-color: var(--primary-button-enabled); } diff --git a/packages/ui/src/components/Dropdown.svelte b/packages/ui/src/components/Dropdown.svelte index 14c6b62a76..0c6f29dd89 100644 --- a/packages/ui/src/components/Dropdown.svelte +++ b/packages/ui/src/components/Dropdown.svelte @@ -19,7 +19,7 @@ import Label from './Label.svelte' export let icon: Asset | AnySvelteComponent | undefined = undefined - export let label: IntlString + export let label: IntlString | undefined = undefined export let placeholder: IntlString export let items: ListItem[] = [] export let selected: ListItem | undefined = undefined diff --git a/packages/ui/src/components/DropdownPopup.svelte b/packages/ui/src/components/DropdownPopup.svelte index e5be04b7e1..230fe1c46c 100644 --- a/packages/ui/src/components/DropdownPopup.svelte +++ b/packages/ui/src/components/DropdownPopup.svelte @@ -68,23 +68,28 @@ {/each} diff --git a/packages/ui/src/components/EditBox.svelte b/packages/ui/src/components/EditBox.svelte index b8ce71b202..8ad4d73d01 100644 --- a/packages/ui/src/components/EditBox.svelte +++ b/packages/ui/src/components/EditBox.svelte @@ -23,8 +23,8 @@ export let label: IntlString | undefined = undefined export let icon: Asset | AnySvelteComponent | undefined = undefined - export let maxWidth: string | undefined - export let value: string | number | undefined + export let maxWidth: string | undefined = undefined + export let value: string | number | undefined = undefined export let placeholder: IntlString = plugin.string.EditBoxPlaceholder export let placeholderParam: any | undefined = undefined export let format: 'text' | 'password' | 'number' = 'text' diff --git a/packages/ui/src/components/Progress.svelte b/packages/ui/src/components/Progress.svelte index ec0d96e255..ce9f8302b1 100644 --- a/packages/ui/src/components/Progress.svelte +++ b/packages/ui/src/components/Progress.svelte @@ -37,7 +37,9 @@
diff --git a/packages/ui/src/components/TextAriaEditor.svelte b/packages/ui/src/components/TextAriaEditor.svelte index c22f49f632..ba47ca1682 100644 --- a/packages/ui/src/components/TextAriaEditor.svelte +++ b/packages/ui/src/components/TextAriaEditor.svelte @@ -12,7 +12,7 @@ export let width: string | undefined = undefined export let height: string | undefined = undefined export let submitLabel: IntlString = ui.string.Save - export let placeholder: IntlString | undefined + export let placeholder: IntlString | undefined = undefined const dispatch = createEventDispatcher() let isEditing = false diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts index a0d538e052..4b5bbd2463 100644 --- a/packages/ui/src/index.ts +++ b/packages/ui/src/index.ts @@ -25,6 +25,7 @@ export type { AnySvelteComponent, Action, LabelAndProps, + ListItem, TooltipAlignment, AnySvelteComponentWithProps, Location, diff --git a/packages/ui/src/types.ts b/packages/ui/src/types.ts index 13885200c5..2c4a214822 100644 --- a/packages/ui/src/types.ts +++ b/packages/ui/src/types.ts @@ -93,6 +93,9 @@ export interface ListItem { _id: string label: string image?: string + isSelectable?: boolean + fontWeight?: 'normal' | 'medium' | 'semi-bold' + paddingLeft?: number } export interface DropdownTextItem { diff --git a/plugins/board-assets/lang/en.json b/plugins/board-assets/lang/en.json index 76ea2a1173..cc57c02b2b 100644 --- a/plugins/board-assets/lang/en.json +++ b/plugins/board-assets/lang/en.json @@ -38,6 +38,10 @@ "NoColor": "No color.", "NoColorInfo": "This won't show up on the front of cards.", "Checklist": "Checklist", + "AddChecklistItem": "Add an item", + "ChecklistDropdownNone": "(none)", + "ShowDoneChecklistItems": "Show checked items ({done})", + "HideDoneChecklistItems": "Hide checked items", "Dates": "Dates", "Attachments": "Attachments", "AddAttachment": "Add an attachment", diff --git a/plugins/board-assets/lang/ru.json b/plugins/board-assets/lang/ru.json index 01c00364ab..7c8b2a4ba2 100644 --- a/plugins/board-assets/lang/ru.json +++ b/plugins/board-assets/lang/ru.json @@ -38,6 +38,10 @@ "NoColor": "Без цвета.", "NoColorInfo": "Не будет показываться на доске.", "Checklist": "Списки", + "AddChecklistItem": "Добавить", + "ChecklistDropdownNone": "(не выбрано)", + "ShowDoneChecklistItems": "Показать отмеченные ({done})", + "HideDoneChecklistItems": "Скрыть отмеченные", "Dates": "Дата", "Attachments": "Прикрепленное", "AddAttachment": "Прикрепить", diff --git a/plugins/board-resources/src/components/EditCard.svelte b/plugins/board-resources/src/components/EditCard.svelte index fbbeb11850..64d080e4df 100644 --- a/plugins/board-resources/src/components/EditCard.svelte +++ b/plugins/board-resources/src/components/EditCard.svelte @@ -19,7 +19,7 @@ import { Panel } from '@anticrm/panel' import { getResource } from '@anticrm/platform' import { createQuery, getClient } from '@anticrm/presentation' - import type { State } from '@anticrm/task' + import type { State, TodoItem } from '@anticrm/task' import task from '@anticrm/task' import { StyledTextBox } from '@anticrm/text-editor' import { Button, EditBox, Icon, Label } from '@anticrm/ui' @@ -30,6 +30,7 @@ import { updateCard } from '../utils/CardUtils' import CardActions from './editor/CardActions.svelte' import CardAttachments from './editor/CardAttachments.svelte' + import CardChecklist from './editor/CardChecklist.svelte' import CardDetails from './editor/CardDetails.svelte' export let _id: Ref @@ -38,20 +39,33 @@ const client = getClient() const cardQuery = createQuery() const stateQuery = createQuery() + const checklistsQuery = createQuery() let object: Card | undefined let state: State | undefined let handleMove: (e: Event) => void + let checklists: TodoItem[] = [] - $: cardQuery.query(_class, { _id }, async (result) => { + function change (field: string, value: any) { + if (object) { + updateCard(client, object, field, value) + } + } + + $: cardQuery.query(_class, { _id }, (result) => { object = result[0] }) $: object?.state && - stateQuery.query(task.class.State, { _id: object.state }, async (result) => { + stateQuery.query(task.class.State, { _id: object.state }, (result) => { state = result[0] }) + $: object && + checklistsQuery.query(task.class.TodoItem, { space: object.space, attachedTo: object._id }, (result) => { + checklists = result + }) + getCardActions(client, { _id: board.cardAction.Move }).then(async (result) => { if (result[0]?.handler) { const handler = await getResource(result[0].handler) @@ -63,12 +77,6 @@ } }) - function change (field: string, value: any) { - if (object) { - updateCard(client, object, field, value) - } - } - onMount(() => { dispatch('open', { ignoreKeys: ['comments', 'number', 'title'] }) }) @@ -130,8 +138,9 @@
- - + {#each checklists as checklist} + + {/each} diff --git a/plugins/board-resources/src/components/editor/CardActivity.svelte b/plugins/board-resources/src/components/editor/CardActivity.svelte deleted file mode 100644 index 12f0954382..0000000000 --- a/plugins/board-resources/src/components/editor/CardActivity.svelte +++ /dev/null @@ -1,57 +0,0 @@ - - - -{#if value !== undefined} -
-
-
- -
-
-
-
-
-
-
- -
-
- {#if isActivityShown === true} - - - - {/if} -
-{/if} diff --git a/plugins/board-resources/src/components/editor/CardChecklist.svelte b/plugins/board-resources/src/components/editor/CardChecklist.svelte new file mode 100644 index 0000000000..93ffd072fb --- /dev/null +++ b/plugins/board-resources/src/components/editor/CardChecklist.svelte @@ -0,0 +1,222 @@ + + + +{#if value !== undefined} +
+
+
+ +
+ {#if isEditingName} +
+ { + isEditingName = false + }} + /> +
+ {:else} +
{ + isEditingName = true + }} + > + {value.name} +
+ {#if done > 0} +
+
+ {/if} +
+
+
+ {checklistItems.length > 0 ? Math.round((done / checklistItems.length) * 100) : 0}% +
+
+ +
+
+ {#each checklistItems.filter((item) => !hideDoneItems || !item.done) as item} +
{ + hovered = item._id + }} + on:focus={() => { + hovered = item._id + }} + on:mouseout={() => { + hovered = undefined + }} + on:blur={() => { + hovered = undefined + }} + > +
+ setDoneToChecklistItem(item, event)} /> +
+ {#if editingItemId === item._id} +
+ { + editingItemId = undefined + updateItemName(item, event.detail) + }} + on:cancel={() => { + editingItemId = undefined + }} + /> +
+ {:else} +
{ + editingItemId = item._id + }} + > + +
+
+
+ {/if} +
+ {/each} +
+
+ {#if isAddingItem} +
+ { + newItemName = '' + isAddingItem = false + }} + /> +
+ {:else} +
+
+{/if} diff --git a/plugins/board-resources/src/components/popups/AddChecklist.svelte b/plugins/board-resources/src/components/popups/AddChecklist.svelte new file mode 100644 index 0000000000..ed840535f9 --- /dev/null +++ b/plugins/board-resources/src/components/popups/AddChecklist.svelte @@ -0,0 +1,152 @@ + + +
+
+
+
+ +
+
+
+
+
+
+
+ +
+ +
+
+ +
+
+
+ +
+ +
+
+ + +
diff --git a/plugins/board-resources/src/index.ts b/plugins/board-resources/src/index.ts index 53331ba936..949e5edeb7 100644 --- a/plugins/board-resources/src/index.ts +++ b/plugins/board-resources/src/index.ts @@ -27,6 +27,7 @@ import CreateCard from './components/CreateCard.svelte' import EditCard from './components/EditCard.svelte' import KanbanCard from './components/KanbanCard.svelte' import KanbanView from './components/KanbanView.svelte' +import AddChecklist from './components/popups/AddChecklist.svelte' import AttachmentPicker from './components/popups/AttachmentPicker.svelte' import CardLabelsPopup from './components/popups/CardLabelsPopup.svelte' import MoveCard from './components/popups/MoveCard.svelte' @@ -73,6 +74,10 @@ async function showCardLabelsPopup (object: Card, client: Client, e?: Event): Pr showPopup(CardLabelsPopup, { object }, getPopupAlignment(e)) } +async function showChecklistsPopup (object: Card, client: Client, e?: Event): Promise { + showPopup(AddChecklist, { object }, getPopupAlignment(e)) +} + async function showEditMembersPopup (object: Card, client: Client, e?: Event): Promise { showPopup( UsersPopup, @@ -126,6 +131,7 @@ export default async (): Promise => ({ SendToBoard: unarchiveCard, Delete: showDeleteCardPopup, Members: showEditMembersPopup, + Checklist: showChecklistsPopup, Copy: showCopyCardPopup, Cover: showCoverPopup }, diff --git a/plugins/board-resources/src/plugin.ts b/plugins/board-resources/src/plugin.ts index 5d029c2332..aa8e1519bb 100644 --- a/plugins/board-resources/src/plugin.ts +++ b/plugins/board-resources/src/plugin.ts @@ -59,6 +59,10 @@ export default mergeIds(boardId, board, { NoColor: '' as IntlString, NoColorInfo: '' as IntlString, Checklist: '' as IntlString, + AddChecklistItem: '' as IntlString, + ChecklistDropdownNone: '' as IntlString, + ShowDoneChecklistItems: '' as IntlString, + HideDoneChecklistItems: '' as IntlString, Dates: '' as IntlString, Attachments: '' as IntlString, AddAttachment: '' as IntlString, diff --git a/plugins/view-resources/src/index.ts b/plugins/view-resources/src/index.ts index c2a5bee4bd..f62c72a692 100644 --- a/plugins/view-resources/src/index.ts +++ b/plugins/view-resources/src/index.ts @@ -55,7 +55,7 @@ export { default as LinkPresenter } from './components/LinkPresenter.svelte' export * from './context' export * from './selection' export { buildModel, getCollectionCounter, getObjectPresenter, LoadingProps } from './utils' -export { Table, TableView, DocAttributeBar, EditDoc, ColorsPopup, Menu, SpacePresenter, UpDownNavigator } +export { HTMLPresenter, Table, TableView, DocAttributeBar, EditDoc, ColorsPopup, Menu, SpacePresenter, UpDownNavigator } export default async (): Promise => ({ actionImpl: actionImpl,