Created
July 18, 2019 12:55
-
-
Save d4rekanguok/5115aaec2e699e11cbeaf79644e0fce2 to your computer and use it in GitHub Desktop.
custom reorder widget for netlify cms
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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