feat: add kanban todo progress
This commit is contained in:
@@ -1,4 +1,7 @@
|
|||||||
import { styled } from '@toeverything/components/ui';
|
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 { useBlock } from '../hooks';
|
||||||
import { BlockRenderProvider } from './Context';
|
import { BlockRenderProvider } from './Context';
|
||||||
import { NullBlockRender, RenderBlock, RenderBlockProps } from './RenderBlock';
|
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 = ({
|
const KanbanChildrenRender = ({
|
||||||
blockId,
|
blockId,
|
||||||
activeBlock,
|
activeBlock,
|
||||||
}: RenderBlockProps & { activeBlock?: string | null }) => {
|
}: RenderBlockProps & { activeBlock?: string | null }) => {
|
||||||
const { block } = useBlock(blockId);
|
const { block } = useBlock(blockId);
|
||||||
|
const progress = useBlockProgress(block);
|
||||||
|
|
||||||
if (!block) {
|
if (!block || !block?.childrenIds.length) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BlockRenderProvider blockRender={NullBlockRender}>
|
<BlockRenderProvider blockRender={NullBlockRender}>
|
||||||
|
<ProgressBar progress={progress} />
|
||||||
{block?.childrenIds.map(childId => (
|
{block?.childrenIds.map(childId => (
|
||||||
<ChildBorder key={childId} active={activeBlock === childId}>
|
<ChildBorder key={childId} active={activeBlock === childId}>
|
||||||
<RenderBlock blockId={childId} />
|
<RenderBlock blockId={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 }) => ({
|
const ChildBorder = styled(BlockBorder)(({ active, theme }) => ({
|
||||||
border: `1px solid ${active ? theme.affine.palette.primary : '#E0E6EB'}`,
|
border: `1px solid ${active ? theme.affine.palette.primary : '#E0E6EB'}`,
|
||||||
margin: '4px 0',
|
margin: '4px 0',
|
||||||
|
|||||||
Reference in New Issue
Block a user