Skip to content

Instantly share code, notes, and snippets.

@d4rekanguok
Created July 18, 2019 12:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save d4rekanguok/5115aaec2e699e11cbeaf79644e0fce2 to your computer and use it in GitHub Desktop.
Save d4rekanguok/5115aaec2e699e11cbeaf79644e0fce2 to your computer and use it in GitHub Desktop.
custom reorder widget for netlify cms
import differenceBy from 'lodash/differenceBy'
export const hasItem = <T>(data: T[], item: T, key: keyof T): boolean => {
return data.some(datum => datum[key] === item[key])
}
export const removeOutdatedItem = <T>(
data: T[],
outdated: T[],
key: keyof T
): T[] =>
data.filter(item => {
return !outdated.some(outdatedItem => outdatedItem[key] === item[key])
})
interface DiffArgs<T> {
currentOrder: T[];
data: T[];
key: keyof T;
}
interface DiffResult<T> {
changed: boolean;
newOrder: T[];
}
export const diff = <T>({
currentOrder,
data,
key,
}: DiffArgs<T>): DiffResult<T> => {
const outdatedItem = differenceBy(currentOrder, data, key)
const newItem = differenceBy(data, currentOrder, key)
if (outdatedItem.length === 0 && newItem.length === 0) {
return {
changed: false,
newOrder: currentOrder,
}
}
const newOrder = removeOutdatedItem(currentOrder, outdatedItem, key).concat(
newItem
)
return {
changed: true,
newOrder,
}
}
export const reorder = (list, startIndex, endIndex) => {
const result = Array.from(list)
const [removed] = result.splice(startIndex, 1)
result.splice(endIndex, 0, removed)
return result
}
import * as React from 'react'
import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd'
import styled from '@emotion/styled'
import { reorder, diff } from './utils'
import { WidgetProps } from './widget'
const StyledBackground = styled.div<{ isDraggingOver: boolean }>`
background: ${({ isDraggingOver }) =>
isDraggingOver ? 'lightblue' : '#dedee2'};
border-radius: 0.25rem;
border-top-left-radius: 0;
padding: 1rem;
max-width: 24rem;
box-sizing: border-box;
`
const StyledItem = styled.div<{ isDragging: boolean }>`
background: #fff;
color: #222;
border-radius: 0.25rem;
padding: 0.5rem;
box-sizing: border-box;
margin-bottom: 0.25rem;
box-shadow: ${({ isDragging }) =>
isDragging
? '0 6px 12px 0 rgba(0, 0, 0, 0.4)'
: '0 2px 6px 0 rgba(0, 0, 0, 0.2)'};
`
export class OrderWidget extends React.Component<WidgetProps> {
public state = {
data: [],
}
public async componentDidMount() {
const { query, forID, value, onChange } = this.props
// collection id field empty search: return all entries
// vvvvvvvv vvvvvvvv vv
const result = await query(forID, 'artists', ['nameEn'], '')
const data = result.payload.response.hits.map(payload => {
// useful data to display
// vvvvvv
const { nameEn, nameKo } = payload.data
return {
nameEn,
nameKo,
}
})
const currentOrder = value.toJS()
const { newOrder, changed } = diff({
currentOrder,
data,
key: 'nameKo',
})
this.setState({ data: newOrder })
if (changed) onChange(newOrder)
}
public handleDragEnd = result => {
const { onChange } = this.props
if (!result.destination) return
const { data } = this.state
const sortedData = reorder(
data,
result.source.index,
result.destination.index
)
this.setState({
data: sortedData,
})
onChange(sortedData)
}
public render() {
const { data } = this.state
if (data.length === 0) return <div>loading...</div>
return (
<DragDropContext onDragEnd={this.handleDragEnd}>
<Droppable droppableId="droppable">
{(provided, snapshot) => (
<StyledBackground
{...provided.droppableProps}
isDraggingOver={snapshot.isDraggingOver}
ref={provided.innerRef}
>
{data.map((item, i) => (
<Draggable
key={item.nameKo}
draggableId={item.nameKo}
index={i}
>
{(provided, snapshot) => (
<StyledItem
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
isDragging={snapshot.isDragging}
>
{item.nameKo} {item.nameEn}
</StyledItem>
)}
</Draggable>
))}
{provided.placeholder}
</StyledBackground>
)}
</Droppable>
</DragDropContext>
)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment