refactor kanban

This commit is contained in:
chenos 2021-08-23 01:23:04 +08:00
parent 959059cfc7
commit 3d5c81618f
6 changed files with 419 additions and 470 deletions

View File

@ -350,7 +350,9 @@ function generateCardItemSchema(component) {
},
Kanban: {
type: 'array',
name: 'kanban1',
'x-component': 'Kanban',
'x-designable-bar': 'Kanban.DesignableBar',
'x-component-props': {},
'x-decorator': 'CardItem',
'x-decorator-props': {
style: {
@ -360,60 +362,11 @@ function generateCardItemSchema(component) {
padding: 0,
},
},
'x-designable-bar': 'Kanban.DesignableBar',
'x-component': 'Kanban',
default: [
{
id: '1',
type: 'A',
title: 'A1',
},
{
id: '2',
type: 'A',
title: 'A2',
},
{
id: '3',
type: 'A',
title: 'A3',
},
{
id: '4',
type: 'B',
title: 'B4',
},
{
id: '5',
type: 'B',
title: 'B5',
},
{
id: '6',
type: 'B',
title: 'B6',
},
{
id: '7',
type: 'C',
title: 'C7',
},
{
id: '8',
type: 'C',
title: 'C8',
},
{
id: '9',
type: 'C',
title: 'C9',
},
],
properties: {
create: {
type: 'void',
title: '添加卡片',
'x-designable-bar': 'Kanban.AddCardDesignableBar',
// 'x-designable-bar': 'Kanban.AddCardDesignableBar',
'x-component': 'Kanban.Card.AddNew',
// 'x-decorator': 'AddNew.Displayed',
'x-component-props': {
@ -446,24 +399,12 @@ function generateCardItemSchema(component) {
name: uid(),
'x-decorator': 'Form',
'x-component': 'Kanban.Card',
'x-designable-bar': 'Kanban.Card.DesignableBar',
'x-read-pretty': true,
'x-decorator-props': {
useResource: '{{ Kanban.useResource }}',
},
properties: {
[uid()]: {
type: 'void',
'x-decorator': 'BlockItem',
'x-decorator-props': {
draggable: false,
},
'x-component': 'Grid',
'x-designable-bar': 'Kanban.Card.DesignableBar',
// 'x-component-props': {
// addNewComponent: 'AddNew.FormItem',
// },
},
useResource: '{{ Kanban.useSingleResource }}',
},
properties: {},
},
view1: {
type: 'void',
@ -474,7 +415,7 @@ function generateCardItemSchema(component) {
useOkAction: '{{ Kanban.useUpdateAction }}',
},
'x-decorator-props': {
useResource: '{{ Kanban.useResource }}',
useResource: '{{ Kanban.useSingleResource }}',
},
properties: {
[uid()]: {
@ -1286,8 +1227,9 @@ AddNew.CardItem = observer((props: any) => {
data['x-component-props'][
'collectionName'
] = collectionName;
data['x-component-props']['groupName'] =
field.name;
data['x-component-props']['groupField'] = {
name: field.name,
};
}
if (isGridBlock(schema)) {
path.pop();

View File

@ -87,27 +87,15 @@ export const CardDesignableBar = observer((props) => {
return;
}
let data: ISchema = {
type: 'void',
'x-component': 'Grid.Row',
properties: {
[uid()]: {
type: 'void',
'x-component': 'Grid.Col',
properties: {
[uid()]: {
key: uid(),
name: uid(),
type: 'void',
'x-decorator': 'Form.Field.Item',
'x-designable-bar':
'Form.Field.DesignableBar',
// 'x-designable-bar': 'Form.Field.DesignableBar',
'x-component': 'Form.Field',
'x-component-props': {
fieldName: field.name,
},
},
},
},
},
};
const s = appendChild(data);
await createSchema(s);

View File

@ -1,22 +1,61 @@
import { ISchema } from '@formily/react';
import React from 'react';
import { SchemaRenderer } from '../../';
import { ISchema, SchemaRenderer } from '../../';
import { Kanban } from '..';
import { uid } from '@formily/shared';
const schema: ISchema = {
type: 'array',
name: 'kanban1',
'x-component': 'Kanban',
'x-component-props': {
groupField: {
name: 'type',
enum: [
{
label: 'A',
value: 'A',
color: 'magenta',
},
{
label: 'B',
value: 'B',
color: 'green',
},
{
label: 'C',
value: 'C',
color: 'blue',
},
{
label: 'D',
value: 'D',
color: 'purple',
},
],
},
},
default: [
{
id: '1',
type: 'A',
title: 'A1',
content: (
<p>
Lorem ipsum dolor sit amet, no dolor graeco pro, te sea bonorum
dolorum theophrastus.{' '}
</p>
),
},
{
id: '2',
type: 'A',
title: 'A2',
content: (
<p>
Lorem ipsum dolor sit amet, no dolor graeco pro, te sea bonorum
dolorum theophrastus.{' '}
</p>
),
},
{
id: '3',
@ -27,11 +66,35 @@ const schema: ISchema = {
id: '4',
type: 'B',
title: 'B4',
content: (
<p>
Lorem ipsum dolor sit amet, no dolor graeco pro, te sea bonorum
dolorum theophrastus. Vim ea utamur appetere molestiae, ad harum
alienum indoctum ius. No quo laoreet laboramus comprehensam, eos paulo
integre vivendo eu, an nam alia facilisi consetetur. Pro exerci iisque
et, no amet magna iracundia vim. Vis erant consectetuer te, mei
menandri liberavisse at, no latine consulatu deseruisse eos. Mel an
novum nostrud scripserit, velit virtute delicata eam ad, eum ne etiam
omnesque.
</p>
),
},
{
id: '5',
type: 'B',
title: 'B5',
content: (
<p>
Lorem ipsum dolor sit amet, no dolor graeco pro, te sea bonorum
dolorum theophrastus. Vim ea utamur appetere molestiae, ad harum
alienum indoctum ius. No quo laoreet laboramus comprehensam, eos paulo
integre vivendo eu, an nam alia facilisi consetetur. Pro exerci iisque
et, no amet magna iracundia vim. Vis erant consectetuer te, mei
menandri liberavisse at, no latine consulatu deseruisse eos. Mel an
novum nostrud scripserit, velit virtute delicata eam ad, eum ne etiam
omnesque.
</p>
),
},
{
id: '6',
@ -42,6 +105,12 @@ const schema: ISchema = {
id: '7',
type: 'C',
title: 'C7',
content: (
<p>
Lorem ipsum dolor sit amet, no dolor graeco pro, te sea bonorum
dolorum theophrastus.{' '}
</p>
),
},
{
id: '8',
@ -55,40 +124,79 @@ const schema: ISchema = {
},
],
properties: {
create: {
type: 'void',
title: '添加卡片',
// 'x-designable-bar': 'Kanban.AddCardDesignableBar',
'x-component': 'Kanban.Card.AddNew',
// 'x-decorator': 'AddNew.Displayed',
'x-component-props': {
type: 'text',
icon: 'PlusOutlined',
},
properties: {
modal: {
type: 'void',
title: '新增数据',
'x-decorator': 'Form',
'x-component': 'Action.Drawer',
'x-component-props': {
useOkAction: '{{ Kanban.useCreateAction }}',
},
properties: {
[uid()]: {
type: 'void',
'x-component': 'Grid',
'x-component-props': {
addNewComponent: 'AddNew.FormItem',
},
},
},
},
},
},
card1: {
type: 'void',
name: uid(),
'x-decorator': 'Form',
'x-component': 'Kanban.Card',
properties: {
item1: {
type: 'void',
'x-component': 'Kanban.Item',
properties: {
title: {
type: 'string',
// title: '标题',
'x-designable-bar': 'Kanban.Card.DesignableBar',
'x-read-pretty': true,
'x-decorator': 'FormItem',
'x-component': 'Input',
},
},
'x-decorator-props': {
useResource: '{{ Kanban.useSingleResource }}',
},
properties: {
// [uid()]: {
// type: 'void',
// 'x-decorator': 'BlockItem',
// 'x-decorator-props': {
// draggable: false,
// },
// 'x-component': 'Grid',
// 'x-designable-bar': 'Kanban.Card.DesignableBar',
// // 'x-component-props': {
// // addNewComponent: 'AddNew.FormItem',
// // },
// },
},
},
view1: {
type: 'void',
title: '修改数据',
'x-decorator': 'Form',
'x-component': 'Kanban.Card.View',
properties: {
item1: {
type: 'void',
'x-component': 'Kanban.Item',
properties: {
title: {
type: 'string',
title: '标题',
'x-read-pretty': true,
'x-decorator': 'FormItem',
'x-component': 'Input',
'x-component-props': {
useOkAction: '{{ Kanban.useUpdateAction }}',
},
'x-decorator-props': {
useResource: '{{ Kanban.useSingleResource }}',
},
properties: {
[uid()]: {
type: 'void',
'x-component': 'Grid',
'x-component-props': {
addNewComponent: 'AddNew.FormItem',
},
},
},
@ -97,5 +205,5 @@ const schema: ISchema = {
};
export default () => {
return <SchemaRenderer components={{ Kanban }} schema={schema} />;
return <SchemaRenderer scope={{ Kanban }} components={{ Kanban }} schema={schema} />;
};

View File

@ -1,32 +1 @@
---
title: Kanban - 看板
nav:
title: 组件
path: /client
group:
order: 1
title: Schemas
path: /client/schemas
---
# Kanban - 看板
## Node Tree
<pre lang="tsx">
<Kanban>
<Kanban.Card>
// 看板卡片
<Kanban.Item>
<Input/>
</Kanban.Item>
</Kanban.Card>
<Kanban.Card.View>
// 查看卡片详情
</Kanban.Card.View>
</Kanban>
</pre>
## Examples
<code src="./demos/demo1.tsx" />
<code src="./demos/demo1.tsx"/>

View File

@ -1,4 +1,17 @@
import React, { useEffect, useRef } from 'react';
import {
DndContext,
DragOverlay,
PointerSensor,
useDroppable,
useSensor,
useSensors,
} from '@dnd-kit/core';
import {
SortableContext,
useSortable,
verticalListSortingStrategy,
} from '@dnd-kit/sortable';
import { ArrayField } from '@formily/core';
import {
observer,
RecursionField,
@ -6,164 +19,147 @@ import {
useField,
useForm,
} from '@formily/react';
import {
DndContext,
DragOverlay,
closestCorners,
rectIntersection,
closestCenter,
useSensors,
useSensor,
MouseSensor,
} from '@dnd-kit/core';
import {
SortableContext,
rectSortingStrategy,
verticalListSortingStrategy,
horizontalListSortingStrategy,
} from '@dnd-kit/sortable';
import { useSortable, arrayMove } from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';
import './style.less';
import { useState } from 'react';
import { Card, Spin, Tag } from 'antd';
import { groupBy } from 'lodash';
import React, { createContext, useContext, useRef } from 'react';
import { useState } from 'react';
import { CSS } from '@dnd-kit/utilities';
import cls from 'classnames';
import { Button, Card, Drawer, Tag } from 'antd';
import {
SchemaRenderer,
useDesignable,
} from '../../components/schema-renderer';
import { createContext } from 'react';
import { useContext } from 'react';
import { PlusOutlined } from '@ant-design/icons';
import { uid } from '@formily/shared';
import { DesignableBar } from './DesignableBar';
import './style.less';
import { CollectionProvider, useCollectionContext } from '../../constate';
import { Resource } from '../../resource';
import { useRequest } from 'ahooks';
import { Action } from '../action';
import { Form } from '../form';
import { CardDesignableBar } from './CardDesignableBar';
import { VisibleContext } from '../../context';
import { DesignableBar } from './DesignableBar';
import { useDesignable } from '../../components/schema-renderer';
export function SortableItem(props) {
function Droppable(props) {
const { id, data, ...others } = props;
const { setNodeRef } = useDroppable({
id,
data,
});
return <div ref={setNodeRef} {...others}></div>;
}
function SortableItem(props) {
const { id, data, className, ...others } = props;
const nodeRef = useRef<any>();
const {
isDragging,
attributes,
listeners,
setNodeRef,
isDragging,
transform,
transition,
} = useSortable({
id: props.id,
disabled: props.disabled,
data: {
type: props.type,
nodeRef,
},
id,
data: { ...data, nodeRef },
});
const style = {
...props.style,
transform: CSS.Transform.toString(transform),
transition,
};
return (
<div
className={cls({ isDragging }, props.className)}
{...others}
ref={(el) => {
setNodeRef(el);
nodeRef.current = el;
}}
style={style}
className={cls(className, { isDragging })}
{...attributes}
{...listeners}
>
{/* <div {...listeners}>drag</div> */}
{props.children}
</div>
);
}
const useColumns = () => {
const field = useField<Formily.Core.Models.ArrayField>();
const { getField } = useCollectionContext();
let groupField = field.componentProps.groupField;
const groupName = field.componentProps.groupName;
const collectionField = getField(groupName);
if (collectionField) {
groupField = collectionField?.uiSchema;
}
const values = field.value;
const columns = groupField?.enum?.map((group) => {
return {
...group,
items: values?.filter((item) => item[groupName] === group.value) || [],
};
});
console.log('useColumns', { values, columns });
return { values, columns };
};
interface KanbanCardContextProps {
index: number;
record?: any;
viewSchema: Schema;
interface KanbanContextProps {
props?: any;
service?: any;
resource?: Resource;
[key: string]: any;
}
const KanbanCardContext = createContext<KanbanCardContextProps>(null);
interface KanbanCardContextProps {
record?: any;
[key: string]: any;
}
export const KanbanContext = createContext<any>(null);
export const KanbanColumnContext = createContext<any>(null);
interface KanbanColumnContextProps {
[key: string]: any;
}
export const KanbanContext = createContext<KanbanContextProps>(null);
export const KanbanColumnContext =
createContext<KanbanColumnContextProps>(null);
export const KanbanCardContext = createContext<KanbanCardContextProps>(null);
export const useKanban = () => {
return useContext(KanbanContext);
};
class MyMouseSensor extends MouseSensor {
static activators = [
{
eventName: 'onMouseDown' as const,
handler: (event) => {
if (event.target.tagName === 'DIV') {
return true;
}
console.log('event.target.tagName', event.target.tagName);
event.target;
return false;
},
},
];
constructor(props) {
super(props);
}
}
const KanbanColumn = (props) => {
const option = useContext(KanbanColumnContext);
const { field, schemas } = useKanban();
const { items } = props;
return (
<SortableContext
// id={option.value}
items={items || []}
strategy={verticalListSortingStrategy}
>
{items?.map((item) => {
const index = field.value?.findIndex((val) => val.id === item.id);
return (
<SortableItem
className={'nb-kanban-item'}
key={item.id}
id={item.id}
data={{ type: 'card', columnId: option.value }}
>
<KanbanCardContext.Provider
value={{ index, schemas, record: item }}
>
{/* <Card bordered={false}>{item.id}</Card> */}
<RecursionField
name={index}
schema={schemas.get('Kanban.Card')}
/>
</KanbanCardContext.Provider>
</SortableItem>
);
})}
</SortableContext>
);
};
const InternalKanban = observer((props: any) => {
const field = useField<Formily.Core.Models.ArrayField>();
const groupName = field.componentProps.groupName;
const { values, columns } = useColumns();
const { schema } = useDesignable();
const { getField } = useCollectionContext();
const collectionField = getField(props.groupField?.name);
const groupField = {
...collectionField?.uiSchema,
...props.groupField,
};
const field = useField<ArrayField>();
const sensors = useSensors(
useSensor(PointerSensor, {
activationConstraint: {
distance: 10,
},
}),
);
const groups = groupBy(field.value, groupField.name);
const { collectionName } = props;
const cardSchema = schema.reduceProperties((prev, current) => {
if (current['x-component'] === 'Kanban.Card') {
return current;
}
return prev;
}, null);
const cardViewSchema = schema.reduceProperties((prev, current) => {
if (current['x-component'] === 'Kanban.Card.View') {
return current;
}
return prev;
}, null);
const addCardSchema = schema.reduceProperties((prev, current) => {
if (current['x-component'] === 'Kanban.Card.AddNew') {
return current;
}
return prev;
}, null);
const resource = Resource.make(collectionName);
const service = useRequest(
(params) => {
@ -180,163 +176,153 @@ const InternalKanban = observer((props: any) => {
onSuccess(data) {
field.setValue(data);
},
manual: true,
// manual: true,
// refreshDeps: [props.fieldNames],
},
);
useEffect(() => {
service.run({
defaultFilter: props?.defaultFilter,
sort: 'sort',
const { schema } = useDesignable();
const [schemas, setSchemas] = useState(() => {
const schemas = new Map<string, Schema>();
schema.reduceProperties((map, current) => {
if (current['x-component'] === 'Kanban.Card') {
map.set('Kanban.Card', current);
}
if (current['x-component'] === 'Kanban.Card.AddNew') {
map.set('Kanban.Card.AddNew', current);
}
if (current['x-component'] === 'Kanban.Card.View') {
map.set('Kanban.Card.View', current);
}
return map;
}, schemas);
return schemas;
});
}, [props.defaultFilter]);
const [dragOverlayContent, setDragOverlayContent] = useState('');
const [style, setStyle] = useState({});
const containerRef = useRef<HTMLDivElement>();
console.log({ style });
const sensors = useSensors(useSensor(MyMouseSensor));
const addNewCardSchema = schemas.get('Kanban.Card.AddNew');
console.log('field.value', schemas);
return (
<KanbanContext.Provider value={{ field, resource, service, props }}>
<div>
{/* <div>
<Button></Button>
</div> */}
<div className={'kanban'}>
<div ref={containerRef} className={'kanban-container'}>
<KanbanContext.Provider
value={{ field, resource, service, schemas, props }}
>
<DndContext
sensors={sensors}
onDragStart={(event) => {
const el = event?.active?.data?.current?.nodeRef
?.current as HTMLElement;
console.log(event, el);
setDragOverlayContent(el?.outerHTML);
setStyle({
width: el.clientWidth,
height: containerRef.current?.clientHeight,
});
onDragMove={({ active, over }) => {
const overId = over?.id;
const activeId = active?.id;
if (!overId || !activeId) {
return;
}
if (overId === activeId) {
return;
}
const overType = over?.data?.current?.type;
const activeItem = field.value.find((item) => item.id === activeId);
if (overType === 'column') {
if (overId === activeItem?.[groupField.name]) {
return;
}
const len = groups?.[overId]?.length;
if (len > 0) {
const last = groups?.[overId]?.[len - 1];
const activeIndex = field.value.findIndex(
(item) => item.id === activeId,
);
const overIndex = field.value.findIndex(
(item) => item.id === last.id,
);
console.log({ overId, last, overIndex, activeIndex });
field.move(activeIndex, overIndex);
}
activeItem[groupField.name] = overId;
} else {
const overColumnId = over?.data?.current?.columnId;
const activeColumnId = active?.data?.current?.columnId;
if (!overColumnId || !activeColumnId) {
return;
}
if (overColumnId !== activeColumnId) {
activeItem[groupField.name] = overColumnId;
const activeIndex = field.value.findIndex(
(item) => item.id === activeId,
);
const overIndex = field.value.findIndex(
(item) => item.id === overId,
);
console.log({ overId, overIndex, activeIndex });
field.move(activeIndex, overIndex);
}
}
}}
collisionDetection={closestCenter}
onDragEnd={({ active, over }) => {
const source = values.find((item) => item.id === active?.id);
const target = values.find((item) => item.id === over?.id);
if (source && target) {
const fromIndex = values.findIndex(
(item) => item.id === active?.id,
const overId = over?.id;
const activeId = active?.id;
if (!overId || !activeId) {
return;
}
if (overId === activeId) {
return;
}
const overType = over?.data?.current?.type;
if (overType !== 'column') {
const overColumnId = over?.data?.current?.columnId;
const activeColumnId = active?.data?.current?.columnId;
if (!overColumnId || !activeColumnId) {
return;
}
if (overColumnId !== activeColumnId) {
return;
}
const activeIndex = field.value.findIndex(
(item) => item.id === activeId,
);
const toIndex = values.findIndex(
(item) => item.id === over?.id,
const overIndex = field.value.findIndex(
(item) => item.id === overId,
);
// setValues((items) => {
// const fromIndex = items.findIndex(
// (item) => item.id === active?.id,
// );
// const toIndex = items.findIndex(
// (item) => item.id === over?.id,
// );
// return arrayMove(items, fromIndex, toIndex);
// });
field.move(fromIndex, toIndex);
}
}}
onDragOver={({ active, over }) => {
if (!over) {
return;
}
if (active?.id === over?.id) {
return;
}
const source = values.find((item) => item.id === active?.id);
if (source && over?.data?.current?.type === 'column') {
source[groupName] = over.id;
return;
}
console.log('active.id', active.id, over?.data?.current);
const target = values.find((item) => item.id === over?.id);
if (source && target) {
if (source[groupName] !== target[groupName]) {
source[groupName] = target[groupName];
}
field.move(activeIndex, overIndex);
}
}}
>
<DragOverlay
style={{ ...style }}
// style={{ pointerEvents: 'none' }}
>
<div
className={'nb-kanban-drag-overlay'}
style={{
...style,
}}
dangerouslySetInnerHTML={{ __html: dragOverlayContent }}
/>
<DragOverlay style={{ background: 'yellow' }}>
<div>aaa</div>
</DragOverlay>
<SortableContext
strategy={horizontalListSortingStrategy}
items={
columns?.map((column) => ({
...column,
id: column.value,
})) || []
}
<Spin spinning={service.loading}>
<div
className={'nb-kanban-board'}
style={{
// display: 'flex',
// flexDirection: 'row',
userSelect: 'none',
}}
>
{columns?.map((column) => (
<SortableItem
id={column.value}
key={column.value}
type={'column'}
disabled
className={'column'}
>
<KanbanColumnContext.Provider value={column}>
<div className={'column-title'}>
<Tag color={column.color}>{column.label}</Tag>
</div>
<SortableContext
strategy={verticalListSortingStrategy}
items={column.items}
>
{column.items.map((item) => {
const index = values.findIndex(
(value) => value.id === item.id,
<div className={'nb-kanban-container'}>
{groupField?.enum?.map((option) => {
const items = field.value?.filter(
(item) => item?.[groupField.name] === option.value,
);
return (
<SortableItem
key={item.id}
className={'item'}
id={item.id}
// disabled
type={'item'}
>
<KanbanCardContext.Provider
value={{
index: index,
record: item,
viewSchema: cardViewSchema,
<Droppable
id={option.value}
data={{
type: 'column',
}}
className={'nb-kanban-column'}
>
<KanbanColumnContext.Provider value={option}>
<div className={'nb-kanban-column-header'}>
<Tag color={option.color}>{option.label}</Tag>
</div>
<KanbanColumn items={items} />
<RecursionField
name={index}
schema={cardSchema}
/>
</KanbanCardContext.Provider>
</SortableItem>
);
})}
</SortableContext>
<RecursionField
name={addCardSchema?.name}
schema={addCardSchema}
name={addNewCardSchema.name}
schema={addNewCardSchema}
/>
</KanbanColumnContext.Provider>
</SortableItem>
))}
</SortableContext>
</Droppable>
);
})}
</div>
</div>
</Spin>
</DndContext>
</div>
</div>
</div>
</KanbanContext.Provider>
);
});
@ -352,13 +338,13 @@ export const Kanban: any = observer((props: any) => {
Kanban.useCreateAction = () => {
const { service, resource, props } = useKanban();
const column = useContext(KanbanColumnContext);
const groupName = props.groupName;
const groupField = props.groupField;
const form = useForm();
return {
async run() {
await resource.create({
...form.values,
[groupName]: column.value,
[groupField.name]: column.value,
});
await form.reset();
return service.refresh();
@ -380,7 +366,7 @@ Kanban.useUpdateAction = () => {
};
};
Kanban.useResource = ({ onSuccess }) => {
Kanban.useSingleResource = ({ onSuccess }) => {
const { props } = useKanban();
const { collection } = useCollectionContext();
const ctx = useContext(KanbanCardContext);
@ -408,7 +394,7 @@ Kanban.useResource = ({ onSuccess }) => {
Kanban.Card = observer((props) => {
const [visible, setVisible] = useState(false);
const { index, viewSchema } = useContext(KanbanCardContext);
const { index, schemas } = useContext(KanbanCardContext);
const { DesignableBar } = useDesignable();
const { children, ...others } = props;
return (
@ -421,9 +407,9 @@ Kanban.Card = observer((props) => {
{...others}
>
{children}
<DesignableBar />
</Card>
<RecursionField name={index} schema={viewSchema} />
<DesignableBar />
<RecursionField name={index} schema={schemas.get('Kanban.Card.View')} />
</VisibleContext.Provider>
);
});

View File

@ -1,80 +1,31 @@
.column {
.nb-kanban-board {
display: flex;
margin: 0;
overflow: auto;
}
.nb-kanban-container {
display: flex;
min-height: 60vh;
}
.nb-kanban-column {
position: relative;
width: 300px;
background: #f9f9f9;
margin-right: 12px;
padding: 12px;
&.isDragging {
opacity: .5;
}
&.add-column {
padding: 0;
margin-right: 0;
background: rgba(241, 139, 98, 0.05);
cursor: pointer;
color: #f18b62;
text-align: center;
justify-content: center;
align-items: center;
display: flex;
.add-column-plus {
position: relative;
&::before {
position: absolute;
width: 1px;
height: 50px;
background: #f18b62;
}
&::after {
position: absolute;
width: 50px;
height: 1px;
background: #f18b62;
}
}
&:hover {
background: rgba(241, 139, 98, 0.1);
}
}
}
.nb-kanban-drag-overlay {
opacity: .8;
}
.column-title {
line-height: 24px;
font-weight: 500;
margin-bottom: 12px;
}
.kanban {
display: flex;
margin: 0;
overflow: auto;
.item {
position: relative;
// background: #f1f1f1;
.nb-kanban-item {
margin-bottom: 12px;
&.isDragging {
opacity: 0.5;
}
opacity: .2;
}
}
.kanban-container {
display: flex;
}
.drag-handle {
position: absolute;
top: 0;
right: 0;
}
.kanban .ant-card-body {
.nb-kanban-item {
position: relative;
padding: 0;
// padding: 0;
> .nb-block-item {
padding: 12px;
@ -117,3 +68,8 @@
}
}
}
.nb-kanban-column-header {
margin-bottom: 12px;
line-height: 32px;
}