300
app/routes/Interface/DragAndDropElements/components/DraggableTable.js
Executable file
300
app/routes/Interface/DragAndDropElements/components/DraggableTable.js
Executable file
@@ -0,0 +1,300 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import uid from 'uuid/v4';
|
||||
import _ from 'lodash';
|
||||
import faker from 'faker/locale/en_US';
|
||||
import {
|
||||
DragDropContext,
|
||||
Droppable,
|
||||
Draggable
|
||||
} from 'react-beautiful-dnd';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import {
|
||||
Table,
|
||||
Badge,
|
||||
Avatar,
|
||||
AvatarAddOn,
|
||||
Progress,
|
||||
Card,
|
||||
CardHeader,
|
||||
CardTitle
|
||||
} from './../../../../components';
|
||||
import { randomAvatar, randomArray } from './../../../../utilities';
|
||||
import { reorder } from './utilities';
|
||||
import classes from './common.scss';
|
||||
|
||||
const allSkills = ['JavaScript', 'Photoshop', 'Management', 'Bootstrap',
|
||||
'PHP', 'Sketch', 'MySQL', 'Mongo', 'Node.js', 'TypeScript'];
|
||||
|
||||
const generateUser = () => ({
|
||||
id: uid(),
|
||||
name: `${faker.name.firstName()} ${faker.name.lastName()}`,
|
||||
title: faker.name.jobType(),
|
||||
avatarUrl: randomAvatar(),
|
||||
status: randomArray(['success', 'warning', 'danger']),
|
||||
skills: _.uniq(_.times(_.random(2, 5), () => randomArray(allSkills))),
|
||||
interviewProgress: _.random(40, 90),
|
||||
portfolio: (Math.round(Math.random())) ? {
|
||||
url: 'http://webkom.co',
|
||||
title: 'www.webkom.co'
|
||||
} : null
|
||||
});
|
||||
|
||||
const getTableClass = (isDraggedOver) =>
|
||||
classNames(classes['table'], {
|
||||
[classes['table--drag-over']]: isDraggedOver
|
||||
});
|
||||
|
||||
const getRowClass = (isDragging) =>
|
||||
classNames(classes['row'], {
|
||||
[classes['row--dragging']]: isDragging
|
||||
});
|
||||
|
||||
// Custom Table Cell - keeps cell width when the row
|
||||
// is detached from the table
|
||||
// ========================================================
|
||||
class TableCell extends React.Component {
|
||||
static propTypes = {
|
||||
children: PropTypes.node,
|
||||
isDragOccurring: PropTypes.bool
|
||||
};
|
||||
|
||||
ref = React.createRef();
|
||||
|
||||
getSnapshotBeforeUpdate(prevProps) {
|
||||
if (!this.ref) {
|
||||
return null;
|
||||
}
|
||||
const ref = this.ref.current;
|
||||
|
||||
const isDragStarting =
|
||||
this.props.isDragOccurring && !prevProps.isDragOccurring;
|
||||
|
||||
if (!isDragStarting) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { width, height } = ref.getBoundingClientRect();
|
||||
|
||||
const snapshot = { width, height };
|
||||
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState, snapshot) {
|
||||
if (!this.ref) {
|
||||
return;
|
||||
}
|
||||
const ref = this.ref.current;
|
||||
|
||||
if (snapshot) {
|
||||
if (ref.style.width === snapshot.width) {
|
||||
return;
|
||||
}
|
||||
ref.style.width = `${snapshot.width}px`;
|
||||
ref.style.height = `${snapshot.height}px`;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.props.isDragOccurring) {
|
||||
return;
|
||||
}
|
||||
|
||||
// inline styles not applied
|
||||
if (ref.style.width == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// no snapshot and drag is finished - clear the inline styles
|
||||
ref.style.removeProperty('height');
|
||||
ref.style.removeProperty('width');
|
||||
}
|
||||
|
||||
render() {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const { children, isDragOccurring, ...otherProps } = this.props;
|
||||
return <td ref={this.ref} {...otherProps}>{children}</td>;
|
||||
}
|
||||
}
|
||||
|
||||
// Draggable Table Row
|
||||
// ========================================================
|
||||
const DraggableRow = (props) => (
|
||||
<Draggable
|
||||
draggableId={props.id}
|
||||
index={props.index}
|
||||
>
|
||||
{(provided, snapshot) => (
|
||||
<tr
|
||||
ref={ provided.innerRef }
|
||||
{ ...provided.draggableProps }
|
||||
className={getRowClass(snapshot.isDragging)}
|
||||
>
|
||||
<TableCell
|
||||
className="align-middle"
|
||||
isDragOccurring={snapshot.isDragging}
|
||||
{ ...provided.dragHandleProps }
|
||||
>
|
||||
<i className="fa fa-fw fa-arrows-v fa-lg d-block mx-auto text-muted" />
|
||||
</TableCell>
|
||||
<TableCell
|
||||
className="align-middle"
|
||||
isDragOccurring={snapshot.isDragging}
|
||||
>
|
||||
<Avatar.Image
|
||||
size="md"
|
||||
className="d-block"
|
||||
src={ props.avatarUrl }
|
||||
addOns={[
|
||||
<AvatarAddOn.Icon
|
||||
className="fa fa-circle"
|
||||
color="white"
|
||||
key="avatar-icon-bg"
|
||||
/>,
|
||||
<AvatarAddOn.Icon
|
||||
className="fa fa-circle"
|
||||
color={ props.status }
|
||||
key="avatar-icon-fg"
|
||||
/>
|
||||
]}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell
|
||||
className="align-middle"
|
||||
isDragOccurring={snapshot.isDragging}
|
||||
>
|
||||
<span className="mt-0 h6 mb-1">
|
||||
{ props.name }
|
||||
</span>
|
||||
<p className="mb-0 text-muted text-truncate">
|
||||
{ props.title }
|
||||
</p>
|
||||
</TableCell>
|
||||
<TableCell
|
||||
className="align-middle"
|
||||
isDragOccurring={snapshot.isDragging}
|
||||
>
|
||||
{_.map(props.skills, (skill, index) => (
|
||||
<Badge
|
||||
key={ index }
|
||||
className={`px-2 ${index > 0 && 'ml-1'}`}
|
||||
>
|
||||
{ skill }
|
||||
</Badge>
|
||||
))}
|
||||
</TableCell>
|
||||
<TableCell
|
||||
className="align-middle"
|
||||
isDragOccurring={snapshot.isDragging}
|
||||
>
|
||||
<Progress value={props.interviewProgress} slim />
|
||||
<span className="fw-500">{ props.interviewProgress }%</span>
|
||||
</TableCell>
|
||||
<TableCell
|
||||
className="text-right align-middle"
|
||||
isDragOccurring={snapshot.isDragging}
|
||||
>
|
||||
{
|
||||
!_.isEmpty(props.portfolio) ? (
|
||||
<a href={props.portfolio.url}>
|
||||
{ props.portfolio.title }
|
||||
</a>
|
||||
) : (
|
||||
<span>-</span>
|
||||
)
|
||||
}
|
||||
</TableCell>
|
||||
</tr>
|
||||
)}
|
||||
</Draggable>
|
||||
);
|
||||
DraggableRow.propTypes = {
|
||||
avatarUrl: PropTypes.string.isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
title: PropTypes.string.isRequired,
|
||||
status: PropTypes.string.isRequired,
|
||||
skills: PropTypes.array.isRequired,
|
||||
interviewProgress: PropTypes.number.isRequired,
|
||||
portfolio: PropTypes.object,
|
||||
index: PropTypes.number.isRequired
|
||||
}
|
||||
|
||||
// Demo Component
|
||||
// ========================================================
|
||||
const initialState = _.times(5, generateUser);
|
||||
|
||||
export class DraggableTable extends React.Component {
|
||||
static propTypes = {
|
||||
className: PropTypes.string,
|
||||
}
|
||||
|
||||
state = {
|
||||
users: initialState
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.onDragEnd = this.onDragEnd.bind(this);
|
||||
}
|
||||
|
||||
onDragEnd({ source, destination }) {
|
||||
if (!destination) {
|
||||
return;
|
||||
}
|
||||
|
||||
const users = reorder(this.state.users,
|
||||
source.index, destination.index);
|
||||
this.setState({ users });
|
||||
}
|
||||
|
||||
recoverInitialState() {
|
||||
this.setState({
|
||||
users: initialState
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Card className={ this.props.className }>
|
||||
<CardHeader className="bg-none bb-0">
|
||||
<CardTitle className="h6">
|
||||
Queue of Candidates
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<DragDropContext onDragEnd={this.onDragEnd}>
|
||||
<Table className="mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th className="bt-0"></th>
|
||||
<th className="bt-0">Photo</th>
|
||||
<th className="bt-0">Name</th>
|
||||
<th className="bt-0">Skills</th>
|
||||
<th className="bt-0">Interview Passed in</th>
|
||||
<th className="bt-0 text-right">Portfolio</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<Droppable droppableId="table">
|
||||
{(provided, snapshot) => (
|
||||
<tbody
|
||||
ref={provided.innerRef}
|
||||
{...provided.droppableProps}
|
||||
className={getTableClass(snapshot.isDraggingOver)}
|
||||
>
|
||||
{_.map(this.state.users, (user, index) => (
|
||||
<DraggableRow
|
||||
key={user.id}
|
||||
index={index}
|
||||
{ ...user }
|
||||
/>
|
||||
))}
|
||||
</tbody>
|
||||
)}
|
||||
</Droppable>
|
||||
</Table>
|
||||
</DragDropContext>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
}
|
178
app/routes/Interface/DragAndDropElements/components/HorizontalLists.js
Executable file
178
app/routes/Interface/DragAndDropElements/components/HorizontalLists.js
Executable file
@@ -0,0 +1,178 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import _ from 'lodash';
|
||||
import classNames from 'classnames';
|
||||
import {
|
||||
DragDropContext,
|
||||
Droppable,
|
||||
Draggable
|
||||
} from 'react-beautiful-dnd';
|
||||
import uid from 'uuid/v4';
|
||||
import {
|
||||
Card,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
Avatar,
|
||||
AvatarAddOn
|
||||
} from './../../../../components';
|
||||
import { randomAvatar, randomArray } from './../../../../utilities';
|
||||
import { reorder, move } from './utilities';
|
||||
import classes from './common.scss';
|
||||
|
||||
const generateItem = () => ({
|
||||
id: uid(),
|
||||
avatarUrl: randomAvatar(),
|
||||
status: randomArray(['success', 'warning', 'danger'])
|
||||
});
|
||||
|
||||
const getListClass = (isDraggedOver) =>
|
||||
classNames(classes['list'], {
|
||||
[classes['list--drag-over']]: isDraggedOver
|
||||
});
|
||||
|
||||
const RowList = (props) => (
|
||||
<Card className={props.className}>
|
||||
<CardHeader className="bg-none">
|
||||
<CardTitle className="h6 mb-0">
|
||||
{ props.title }
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<Droppable
|
||||
droppableId={ props.listId }
|
||||
direction="horizontal"
|
||||
>
|
||||
{(provided, snapshot) => (
|
||||
<div
|
||||
className={`card-body d-flex ${getListClass(snapshot.isDraggingOver)}`}
|
||||
style={{ overflowX: 'auto' }}
|
||||
ref={provided.innerRef}
|
||||
{...provided.droppableProps}
|
||||
>
|
||||
{_.map(props.items, (item, index) => (
|
||||
<Draggable
|
||||
key={item.id}
|
||||
draggableId={item.id}
|
||||
index={index}
|
||||
>
|
||||
{(provided) => (
|
||||
<div
|
||||
className="px-3"
|
||||
ref={provided.innerRef}
|
||||
{...provided.draggableProps}
|
||||
{...provided.dragHandleProps}
|
||||
>
|
||||
<Avatar.Image
|
||||
key={`avatar-${item.id}`}
|
||||
size="lg"
|
||||
className="d-block"
|
||||
src={ item.avatarUrl }
|
||||
addOns={[
|
||||
<AvatarAddOn.Icon
|
||||
className="fa fa-circle"
|
||||
color="white"
|
||||
key="avatar-icon-bg"
|
||||
/>,
|
||||
<AvatarAddOn.Icon
|
||||
className="fa fa-circle"
|
||||
color={ item.status }
|
||||
key="avatar-icon-fg"
|
||||
/>
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</Draggable>
|
||||
))}
|
||||
{ provided.placeholder }
|
||||
</div>
|
||||
)}
|
||||
</Droppable>
|
||||
</Card>
|
||||
)
|
||||
RowList.propTypes = {
|
||||
listId: PropTypes.string.isRequired,
|
||||
items: PropTypes.array.isRequired,
|
||||
title: PropTypes.string.isRequired,
|
||||
className: PropTypes.stirng
|
||||
}
|
||||
const initialState = {
|
||||
listAItems: _.times(_.random(3, 8), generateItem),
|
||||
listBItems: _.times(_.random(3, 8), generateItem),
|
||||
listCItems: _.times(_.random(3, 8), generateItem)
|
||||
};
|
||||
export class HorizontalLists extends React.Component {
|
||||
static propTypes = {
|
||||
className: PropTypes.string
|
||||
}
|
||||
|
||||
state = _.clone(initialState);
|
||||
|
||||
constructor (props) {
|
||||
super(props);
|
||||
|
||||
this.onDragEnd = this.onDragEnd.bind(this);
|
||||
}
|
||||
|
||||
onDragEnd(result) {
|
||||
const { source, destination } = result;
|
||||
|
||||
// dropped outside the list
|
||||
if (!destination) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle List Items
|
||||
if (source.droppableId === destination.droppableId) {
|
||||
const items = reorder(
|
||||
this.state[`${source.droppableId}Items`],
|
||||
source.index,
|
||||
destination.index
|
||||
);
|
||||
|
||||
this.setState({
|
||||
[`${source.droppableId}Items`]: items
|
||||
});
|
||||
} else {
|
||||
const result = move(
|
||||
this.state[`${source.droppableId}Items`],
|
||||
this.state[`${destination.droppableId}Items`],
|
||||
source,
|
||||
destination
|
||||
);
|
||||
|
||||
this.setState(_.mapKeys(result, (val, key) => `${key}Items`));
|
||||
}
|
||||
}
|
||||
|
||||
recoverInitialState() {
|
||||
this.setState(initialState);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { className } = this.props;
|
||||
|
||||
return (
|
||||
<div className={ className }>
|
||||
<DragDropContext onDragEnd={this.onDragEnd}>
|
||||
<RowList
|
||||
listId="listA"
|
||||
items={ this.state.listAItems }
|
||||
title="All Candidates"
|
||||
/>
|
||||
<RowList
|
||||
listId="listB"
|
||||
items={ this.state.listBItems }
|
||||
title="Candidates Interview"
|
||||
className="mt-4"
|
||||
/>
|
||||
<RowList
|
||||
listId="listC"
|
||||
items={ this.state.listCItems }
|
||||
title="Candidates Testing"
|
||||
className="mt-4"
|
||||
/>
|
||||
</DragDropContext>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
267
app/routes/Interface/DragAndDropElements/components/MultipleVerticalLists.js
Executable file
267
app/routes/Interface/DragAndDropElements/components/MultipleVerticalLists.js
Executable file
@@ -0,0 +1,267 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import _ from 'lodash';
|
||||
import {
|
||||
DragDropContext,
|
||||
Droppable,
|
||||
Draggable
|
||||
} from 'react-beautiful-dnd';
|
||||
import uid from 'uuid/v4';
|
||||
import faker from 'faker/locale/en_US';
|
||||
import classNames from 'classnames';
|
||||
import {
|
||||
Card,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
Media,
|
||||
Avatar,
|
||||
AvatarAddOn
|
||||
} from './../../../../components';
|
||||
import { randomAvatar, randomArray } from './../../../../utilities';
|
||||
import { reorder, move } from './utilities';
|
||||
import classes from './common.scss';
|
||||
|
||||
// Utility Functions
|
||||
//=========================================================
|
||||
const generateItem = () => ({
|
||||
id: uid(),
|
||||
type: 'single',
|
||||
name: `${faker.name.firstName()} ${faker.name.lastName()}`,
|
||||
title: faker.name.jobType(),
|
||||
avatarUrl: randomAvatar(),
|
||||
status: randomArray(['success', 'warning', 'danger'])
|
||||
});
|
||||
|
||||
const getListClass = (isDraggedOver) =>
|
||||
classNames(classes['list'], {
|
||||
[classes['list--drag-over']]: isDraggedOver
|
||||
});
|
||||
|
||||
const getItemClass = (isDragging) =>
|
||||
classNames(classes['list-group-item'], {
|
||||
[classes['list-group-item--dragging']]: isDragging
|
||||
});
|
||||
|
||||
// Draggable List Component
|
||||
//=========================================================
|
||||
const VerticalList = React.memo((props) => {
|
||||
return (
|
||||
<Droppable droppableId={ props.listId }>
|
||||
{(provided, snapshot) => (
|
||||
<div
|
||||
ref={provided.innerRef}
|
||||
className={`list-group list-group-flush flex-grow-1 ${getListClass(snapshot.isDraggingOver)}`}
|
||||
>
|
||||
{props.items.map((item, index) => (
|
||||
<Draggable
|
||||
key={item.id}
|
||||
draggableId={item.id}
|
||||
index={index}>
|
||||
{(provided, draggableSnapshot) => (
|
||||
<div
|
||||
ref={provided.innerRef}
|
||||
{...provided.draggableProps}
|
||||
{...provided.dragHandleProps}
|
||||
className={`list-group-item ${getItemClass(draggableSnapshot.isDragging)}`}
|
||||
>
|
||||
<Media>
|
||||
<Media left className="align-self-center pr-3">
|
||||
<i className="fa fa-ellipsis-v text-muted" />
|
||||
</Media>
|
||||
<Media left middle className="mr-4 align-self-center">
|
||||
<Avatar.Image
|
||||
size="md"
|
||||
className="d-block"
|
||||
src={ item.avatarUrl }
|
||||
addOns={[
|
||||
<AvatarAddOn.Icon
|
||||
className="fa fa-circle"
|
||||
color="white"
|
||||
key="avatar-icon-bg"
|
||||
/>,
|
||||
<AvatarAddOn.Icon
|
||||
className="fa fa-circle"
|
||||
color={ item.status }
|
||||
key="avatar-icon-fg"
|
||||
/>
|
||||
]}
|
||||
/>
|
||||
</Media>
|
||||
<Media body>
|
||||
<span className="mt-0 h6 mb-1">
|
||||
{ item.name }
|
||||
</span>
|
||||
<p className="mb-0 text-muted text-truncate">
|
||||
{ item.title }
|
||||
</p>
|
||||
</Media>
|
||||
</Media>
|
||||
</div>
|
||||
)}
|
||||
</Draggable>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</Droppable>
|
||||
);
|
||||
});
|
||||
VerticalList.propTypes = {
|
||||
items: PropTypes.array,
|
||||
listId: PropTypes.string,
|
||||
title: PropTypes.string
|
||||
}
|
||||
|
||||
// Draggable Column Component
|
||||
//=========================================================
|
||||
class Column extends React.Component {
|
||||
static propTypes = {
|
||||
children: PropTypes.node,
|
||||
id: PropTypes.string,
|
||||
index: PropTypes.number,
|
||||
title: PropTypes.string
|
||||
}
|
||||
|
||||
render() {
|
||||
const { children, id, index, title } = this.props;
|
||||
|
||||
return (
|
||||
<Draggable
|
||||
draggableId={id}
|
||||
index={index}
|
||||
>
|
||||
{(provided) => (
|
||||
<div
|
||||
className="col-md-4"
|
||||
ref={provided.innerRef}
|
||||
{...provided.draggableProps}
|
||||
>
|
||||
<Card className="h-100">
|
||||
<CardHeader {...provided.dragHandleProps} className="b-0 bg-none">
|
||||
<CardTitle className="h6 mb-0">
|
||||
<i className="fa fa-ellipsis-v mr-3 text-muted" />
|
||||
{ title }
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
{ children }
|
||||
</Card>
|
||||
</div>
|
||||
)}
|
||||
</Draggable>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Demo Component
|
||||
//=========================================================
|
||||
const initialState = {
|
||||
listAItems: _.times(_.random(2, 4), generateItem),
|
||||
listBItems: _.times(_.random(3, 8), generateItem),
|
||||
listCItems: _.times(_.random(3, 8), generateItem),
|
||||
lists: [
|
||||
{ id: 'listA', title: 'All Candidates' },
|
||||
{ id: 'listB', title: 'Candidates Interview' },
|
||||
{ id: 'listC', title: 'Candidates Testing' }
|
||||
]
|
||||
};
|
||||
export class MultipleVerticalLists extends React.Component {
|
||||
static propTypes = {
|
||||
className: PropTypes.string
|
||||
}
|
||||
|
||||
state = _.clone(initialState);
|
||||
|
||||
constructor (props) {
|
||||
super(props);
|
||||
|
||||
this.onDragEnd = this.onDragEnd.bind(this);
|
||||
}
|
||||
|
||||
onDragEnd(result) {
|
||||
const { source, destination } = result;
|
||||
|
||||
// Swap column positions
|
||||
if (source.droppableId === 'board') {
|
||||
if (destination.droppableId !== 'board') {
|
||||
return;
|
||||
}
|
||||
const lists = reorder(
|
||||
this.state.lists,
|
||||
source.index,
|
||||
destination.index
|
||||
);
|
||||
|
||||
this.setState({ lists });
|
||||
return;
|
||||
}
|
||||
|
||||
// dropped outside the list
|
||||
if (!destination) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle List Items
|
||||
if (source.droppableId === destination.droppableId) {
|
||||
const items = reorder(
|
||||
this.state[`${source.droppableId}Items`],
|
||||
source.index,
|
||||
destination.index
|
||||
);
|
||||
|
||||
this.setState({
|
||||
[`${source.droppableId}Items`]: items
|
||||
});
|
||||
} else {
|
||||
const result = move(
|
||||
this.state[`${source.droppableId}Items`],
|
||||
this.state[`${destination.droppableId}Items`],
|
||||
source,
|
||||
destination
|
||||
);
|
||||
|
||||
this.setState(_.mapKeys(result, (val, key) => `${key}Items`));
|
||||
}
|
||||
}
|
||||
|
||||
recoverInitialState() {
|
||||
this.setState(initialState);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { className } = this.props;
|
||||
const { lists } = this.state;
|
||||
|
||||
return (
|
||||
<div className={ className }>
|
||||
<DragDropContext onDragEnd={this.onDragEnd}>
|
||||
<Droppable
|
||||
droppableId="board"
|
||||
type="COLUMN"
|
||||
direction="horizontal"
|
||||
>
|
||||
{(provided) => (
|
||||
<div
|
||||
className="row"
|
||||
ref={provided.innerRef}
|
||||
{...provided.droppableProps}
|
||||
>
|
||||
{_.map(lists, (list, index) => (
|
||||
<Column
|
||||
id={list.id}
|
||||
index={ index }
|
||||
title={list.title}
|
||||
key={ list.id }
|
||||
>
|
||||
<VerticalList
|
||||
listId={list.id}
|
||||
items={this.state[`${list.id}Items`]}
|
||||
/>
|
||||
</Column>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</Droppable>
|
||||
</DragDropContext>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
43
app/routes/Interface/DragAndDropElements/components/common.scss
Executable file
43
app/routes/Interface/DragAndDropElements/components/common.scss
Executable file
@@ -0,0 +1,43 @@
|
||||
@import "./../../../../styles/variables.scss";
|
||||
|
||||
.list {
|
||||
transition: background-color 200ms cubic-bezier(0.645, 0.045, 0.355, 1.000);
|
||||
|
||||
&--drag-over {
|
||||
background-color: lighten($primary, 45%);
|
||||
}
|
||||
}
|
||||
|
||||
.list-group-item {
|
||||
border-left: 1px solid transparent !important;
|
||||
border-right: 1px solid transparent !important;
|
||||
transition: border-color 200ms cubic-bezier(0.645, 0.045, 0.355, 1.000);
|
||||
|
||||
&:first-child {
|
||||
border-top: 1px solid transparent !important;
|
||||
}
|
||||
|
||||
&--dragging {
|
||||
&:first-child {
|
||||
border-top-color: $primary !important;
|
||||
}
|
||||
border-color: $primary !important;
|
||||
}
|
||||
}
|
||||
|
||||
.table {
|
||||
transition: background-color 200ms cubic-bezier(0.645, 0.045, 0.355, 1.000);
|
||||
|
||||
&--drag-over {
|
||||
background-color: lighten($primary, 45%);
|
||||
}
|
||||
}
|
||||
|
||||
.row {
|
||||
transition: border-color 200ms cubic-bezier(0.645, 0.045, 0.355, 1.000);
|
||||
background: $white;
|
||||
|
||||
&--dragging {
|
||||
border: 1px solid $primary !important;
|
||||
}
|
||||
}
|
3
app/routes/Interface/DragAndDropElements/components/index.js
Executable file
3
app/routes/Interface/DragAndDropElements/components/index.js
Executable file
@@ -0,0 +1,3 @@
|
||||
export * from './MultipleVerticalLists';
|
||||
export * from './DraggableTable';
|
||||
export * from './HorizontalLists';
|
21
app/routes/Interface/DragAndDropElements/components/utilities.js
Executable file
21
app/routes/Interface/DragAndDropElements/components/utilities.js
Executable file
@@ -0,0 +1,21 @@
|
||||
export const reorder = (list, startIndex, endIndex) => {
|
||||
const result = Array.from(list);
|
||||
const [removed] = result.splice(startIndex, 1);
|
||||
result.splice(endIndex, 0, removed);
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
export const move = (source, destination, droppableSource, droppableDestination) => {
|
||||
const sourceClone = Array.from(source);
|
||||
const destClone = Array.from(destination);
|
||||
const [removed] = sourceClone.splice(droppableSource.index, 1);
|
||||
|
||||
destClone.splice(droppableDestination.index, 0, removed);
|
||||
|
||||
const result = {};
|
||||
result[droppableSource.droppableId] = sourceClone;
|
||||
result[droppableDestination.droppableId] = destClone;
|
||||
|
||||
return result;
|
||||
};
|
Reference in New Issue
Block a user