From d6009e5e483da7cb29575b2eb42f59963691fc85 Mon Sep 17 00:00:00 2001 From: lawvs <18554747+lawvs@users.noreply.github.com> Date: Wed, 24 Aug 2022 20:39:45 +0800 Subject: [PATCH] feat: add kanban todo progress --- .../src/render-block/RenderKanbanBlock.tsx | 81 ++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-) diff --git a/libs/components/editor-core/src/render-block/RenderKanbanBlock.tsx b/libs/components/editor-core/src/render-block/RenderKanbanBlock.tsx index 9eb01dbde4..f9b532f6b3 100644 --- a/libs/components/editor-core/src/render-block/RenderKanbanBlock.tsx +++ b/libs/components/editor-core/src/render-block/RenderKanbanBlock.tsx @@ -1,4 +1,7 @@ import { styled } from '@toeverything/components/ui'; +import { Protocol } from '@toeverything/datasource/db-service'; +import { useEffect, useState } from 'react'; +import { AsyncBlock } from '../editor'; import { useBlock } from '../hooks'; import { BlockRenderProvider } from './Context'; import { NullBlockRender, RenderBlock, RenderBlockProps } from './RenderBlock'; @@ -36,18 +39,73 @@ export const KanbanParentBlockRender = ({ ); }; +const useBlockProgress = (block?: AsyncBlock) => { + const [progress, setProgress] = useState(1); + + useEffect(() => { + if (!block) { + return; + } + const updateProgress = async () => { + const children = await block.children(); + const todoChildren = children.filter( + child => child.type === Protocol.Block.Type.todo + ); + const checkedTodoChildren = todoChildren.filter( + child => child.getProperty('checked')?.value === true + ); + setProgress(checkedTodoChildren.length / todoChildren.length); + }; + + let childrenQueue: (() => void)[] = []; + const childrenUnobserve = () => { + childrenQueue.forEach(fn => fn()); + childrenQueue = []; + }; + + const observeChildren = async () => { + const children = await block.children(); + + childrenUnobserve(); + children.forEach(child => { + const unobserve = child.onUpdate(() => { + updateProgress(); + }); + childrenQueue.push(unobserve); + }); + }; + + observeChildren(); + updateProgress(); + + const unobserve = block.onUpdate(() => { + observeChildren(); + updateProgress(); + }); + + return () => { + unobserve(); + childrenUnobserve(); + }; + }, [block]); + + return progress; +}; + const KanbanChildrenRender = ({ blockId, activeBlock, }: RenderBlockProps & { activeBlock?: string | null }) => { const { block } = useBlock(blockId); + const progress = useBlockProgress(block); - if (!block) { + if (!block || !block?.childrenIds.length) { return null; } return ( + {block?.childrenIds.map(childId => ( @@ -82,6 +140,27 @@ const BlockBorder = styled('div')<{ active?: boolean }>( }) ); +const ProgressBar = styled('div')<{ progress?: number }>( + ({ progress = 1 }) => ({ + height: '3px', + width: '100%', + background: '#CFE5FF', + borderRadius: '5px', + overflow: 'hidden', + margin: '12px 0', + + '::after': { + content: '""', + position: 'relative', + display: 'flex', + background: '#60A5FA', + height: '100%', + width: `${(progress * 100).toFixed(2)}%`, + transition: 'ease 0.5s all', + }, + }) +); + const ChildBorder = styled(BlockBorder)(({ active, theme }) => ({ border: `1px solid ${active ? theme.affine.palette.primary : '#E0E6EB'}`, margin: '4px 0',