mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-08 18:30:53 +00:00
kanban supports collapse (#7437)
* kanban supports collapse * optimize * optimize ui --------- Co-authored-by: zhouwenxuan <aries@Mac.local>
This commit is contained in:
@@ -35,7 +35,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.file-details-collapse .file-details-collapse-header .file-details-collapse-header-operation:hover {
|
.file-details-collapse .file-details-collapse-header .file-details-collapse-header-operation:hover {
|
||||||
background-color: #DBDBDB;
|
background-color: #EFEFEF;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
@@ -27,3 +27,25 @@
|
|||||||
color: #666666;
|
color: #666666;
|
||||||
margin-left: 12px;
|
margin-left: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sf-metadata-view-kanban-board-header .board-header-operation-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.board-header-operation-btn .kanban-header-op-btn {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
color: #666666;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.board-header-operation-btn .kanban-header-op-btn.kanban-header-collapse-btn:hover,
|
||||||
|
.board-header-operation-btn .kanban-header-op-btn.kanban-more-operations-toggle:hover {
|
||||||
|
background-color: #EFEFEF;
|
||||||
|
}
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
import React, { useCallback, useMemo, useState } from 'react';
|
import React, { useCallback, useMemo, useRef, useState } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
import classNames from 'classnames';
|
||||||
import CellFormatter from '../../../../../components/cell-formatter';
|
import CellFormatter from '../../../../../components/cell-formatter';
|
||||||
import { gettext } from '../../../../../../utils/constants';
|
import { gettext } from '../../../../../../utils/constants';
|
||||||
import OpMenu from './op-menu';
|
import OpMenu from './op-menu';
|
||||||
@@ -7,9 +8,11 @@ import { CellType } from '../../../../../constants';
|
|||||||
|
|
||||||
import './index.css';
|
import './index.css';
|
||||||
|
|
||||||
const Header = ({ readonly, haveFreezed, value, groupByColumn, cardsQuantity, onDelete, onFreezed, onUnFreezed }) => {
|
const Header = ({ readonly, haveFreezed, value, groupByColumn, cardsQuantity, onDelete, onFreezed, onUnFreezed, isCollapsed, onCollapse }) => {
|
||||||
const [active, setActive] = useState(false);
|
const [active, setActive] = useState(false);
|
||||||
|
|
||||||
|
const headerRef = useRef();
|
||||||
|
|
||||||
const onMouseEnter = useCallback(() => {
|
const onMouseEnter = useCallback(() => {
|
||||||
if (haveFreezed) return;
|
if (haveFreezed) return;
|
||||||
setActive(true);
|
setActive(true);
|
||||||
@@ -20,10 +23,14 @@ const Header = ({ readonly, haveFreezed, value, groupByColumn, cardsQuantity, on
|
|||||||
setActive(false);
|
setActive(false);
|
||||||
}, [haveFreezed]);
|
}, [haveFreezed]);
|
||||||
|
|
||||||
const handelUnFreezed = useCallback((keepActive) => {
|
const keepActive = useCallback((event) => {
|
||||||
|
return event.target.className?.includes('kanban-header-op-btn') || event.target === headerRef.current;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handelUnFreezed = useCallback((event) => {
|
||||||
onUnFreezed();
|
onUnFreezed();
|
||||||
!keepActive && setActive(false);
|
!keepActive(event) && setActive(false);
|
||||||
}, [onUnFreezed]);
|
}, [onUnFreezed, keepActive]);
|
||||||
|
|
||||||
const titleValue = useMemo(() => {
|
const titleValue = useMemo(() => {
|
||||||
if (!value || !groupByColumn) return null;
|
if (!value || !groupByColumn) return null;
|
||||||
@@ -31,9 +38,14 @@ const Header = ({ readonly, haveFreezed, value, groupByColumn, cardsQuantity, on
|
|||||||
return value;
|
return value;
|
||||||
}, [value, groupByColumn]);
|
}, [value, groupByColumn]);
|
||||||
|
|
||||||
|
const handleCollapse = useCallback((event) => {
|
||||||
|
onCollapse();
|
||||||
|
!keepActive(event) && setActive(false);
|
||||||
|
}, [onCollapse, keepActive]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="sf-metadata-view-kanban-board-header" onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave}>
|
<div className="sf-metadata-view-kanban-board-header" onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave}>
|
||||||
<div className="sf-metadata-view-kanban-board-header-title">
|
<div className="sf-metadata-view-kanban-board-header-title" ref={headerRef}>
|
||||||
{value ? (
|
{value ? (
|
||||||
<CellFormatter value={titleValue} field={groupByColumn} readonly={true} />
|
<CellFormatter value={titleValue} field={groupByColumn} readonly={true} />
|
||||||
) : (
|
) : (
|
||||||
@@ -41,8 +53,15 @@ const Header = ({ readonly, haveFreezed, value, groupByColumn, cardsQuantity, on
|
|||||||
)}
|
)}
|
||||||
<span className="cards-quantity">{cardsQuantity}</span>
|
<span className="cards-quantity">{cardsQuantity}</span>
|
||||||
</div>
|
</div>
|
||||||
{value && !readonly && active && (
|
{active && (
|
||||||
<OpMenu onDelete={onDelete} onFreezed={onFreezed} onUnFreezed={handelUnFreezed} />
|
<div className="board-header-operation-btn">
|
||||||
|
{value && !readonly && <OpMenu onDelete={onDelete} onFreezed={onFreezed} onUnFreezed={handelUnFreezed} />}
|
||||||
|
<i
|
||||||
|
className={classNames('sf3-font sf3-font-down kanban-header-op-btn kanban-header-collapse-btn', { 'rotate-90': isCollapsed })}
|
||||||
|
title={isCollapsed ? gettext('Expand') : gettext('Collapse')}
|
||||||
|
onClick={handleCollapse}>
|
||||||
|
</i>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@@ -9,8 +9,7 @@ const OpMenu = ({ onDelete, onFreezed, onUnFreezed }) => {
|
|||||||
const toggle = useCallback((event) => {
|
const toggle = useCallback((event) => {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
if (isShow) {
|
if (isShow) {
|
||||||
const isClickToggleBtn = event.target.className?.includes('kanban-more-operations-toggle');
|
onUnFreezed(event);
|
||||||
onUnFreezed(isClickToggleBtn);
|
|
||||||
} else {
|
} else {
|
||||||
onFreezed();
|
onFreezed();
|
||||||
}
|
}
|
||||||
@@ -35,7 +34,7 @@ const OpMenu = ({ onDelete, onFreezed, onUnFreezed }) => {
|
|||||||
tag="i"
|
tag="i"
|
||||||
role="button"
|
role="button"
|
||||||
tabIndex="0"
|
tabIndex="0"
|
||||||
className="sf-dropdown-toggle sf3-font-more sf3-font kanban-more-operations-toggle"
|
className="sf-dropdown-toggle sf3-font-more sf3-font kanban-header-op-btn kanban-more-operations-toggle"
|
||||||
title={gettext('More operations')}
|
title={gettext('More operations')}
|
||||||
aria-label={gettext('More operations')}
|
aria-label={gettext('More operations')}
|
||||||
data-toggle="dropdown"
|
data-toggle="dropdown"
|
||||||
|
@@ -31,6 +31,7 @@ const Board = ({
|
|||||||
onContextMenu,
|
onContextMenu,
|
||||||
}) => {
|
}) => {
|
||||||
const [isDraggingOver, setDraggingOver] = useState(false);
|
const [isDraggingOver, setDraggingOver] = useState(false);
|
||||||
|
const [isCollapsed, setCollapsed] = useState(false);
|
||||||
const boardName = useMemo(() => `sf_metadata_kanban_board_${board.key}`, [board]);
|
const boardName = useMemo(() => `sf_metadata_kanban_board_${board.key}`, [board]);
|
||||||
const cardsQuantity = useMemo(() => board.children.length, [board.children]);
|
const cardsQuantity = useMemo(() => board.children.length, [board.children]);
|
||||||
|
|
||||||
@@ -54,6 +55,10 @@ const Board = ({
|
|||||||
setTimeout(() => updateDragging(false), 0);
|
setTimeout(() => updateDragging(false), 0);
|
||||||
}, [isDraggingOver, onMove, updateDragging]);
|
}, [isDraggingOver, onMove, updateDragging]);
|
||||||
|
|
||||||
|
const onCollapse = useCallback(() => {
|
||||||
|
setCollapsed(!isCollapsed);
|
||||||
|
}, [isCollapsed]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section draggable={false} className="sf-metadata-view-kanban-board">
|
<section draggable={false} className="sf-metadata-view-kanban-board">
|
||||||
<Header
|
<Header
|
||||||
@@ -65,7 +70,10 @@ const Board = ({
|
|||||||
onDelete={() => deleteOption(board.key)}
|
onDelete={() => deleteOption(board.key)}
|
||||||
onFreezed={onFreezed}
|
onFreezed={onFreezed}
|
||||||
onUnFreezed={onUnFreezed}
|
onUnFreezed={onUnFreezed}
|
||||||
|
isCollapsed={isCollapsed}
|
||||||
|
onCollapse={onCollapse}
|
||||||
/>
|
/>
|
||||||
|
{!isCollapsed && (
|
||||||
<Container
|
<Container
|
||||||
orientation="vertical"
|
orientation="vertical"
|
||||||
groupName={boardName}
|
groupName={boardName}
|
||||||
@@ -114,6 +122,7 @@ const Board = ({
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</Container>
|
</Container>
|
||||||
|
)}
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user