Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 98 additions & 0 deletions example/src/SelectablePig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import React, { Component } from "react";
import Pig from "pig-react";
import imageData from "./imageData.json";

export default class SelectablePig extends Component {
constructor(props) {
super(props)
this.imageData = imageData
this.state = {
selectedItems: []
}
}

handleSelection = item => {
let newSelectedItems = this.state.selectedItems;
if (newSelectedItems.find(selectedItem => selectedItem.id === item.id)) {
newSelectedItems = newSelectedItems.filter(value => value.id !== item.id)
} else {
newSelectedItems = newSelectedItems.concat(item)
}
this.setState({ selectedItems: newSelectedItems })
};

handleSelections = items => {
let newSelectedItems = this.state.selectedItems;
items.forEach(item => {
if (newSelectedItems.find(selectedItem => selectedItem.id === item.id)) {
newSelectedItems = newSelectedItems.filter(value => value.id !== item.id)
} else {
newSelectedItems = newSelectedItems.concat(item)
}
});
this.setState({ selectedItems: newSelectedItems })
};

handleClick = (event, item) => {
//if an image is selectabel, then handle shift click
if (event.shiftKey) {
let lastSelectedElement = this.state.selectedItems.slice(-1)[0]
if (lastSelectedElement === undefined) {
this.handleSelection(item)
return;
}
let indexOfCurrentlySelectedItem = this.imageData.findIndex(image => image.id === item.id)
let indexOfLastSelectedItem = this.imageData.findIndex(image => image.id === lastSelectedElement.id)
if (indexOfCurrentlySelectedItem > indexOfLastSelectedItem) {
this.handleSelections(
this.imageData.slice(
indexOfLastSelectedItem + 1,
indexOfCurrentlySelectedItem + 1
)
);
return;
} else {
this.handleSelections(
this.imageData.slice(
indexOfCurrentlySelectedItem,
indexOfLastSelectedItem
)
)
return
}
}
// if an image is already selected, then we are in selection mode
if (this.state.selectedItems.length > 0) {
this.handleSelection(item)
return
}

// if an image is already the width of the container, don't expand it on click
if (item.style.width >= this.containerWidth) {
this.setState({ activeTileUrl: null })
return
}

this.setState({
// if Tile is already active, deactivate it
activeTileUrl: item.url !== this.state.activeTileUrl ? item.url : null
})
}

render() {
return (
<Pig
imageData={imageData}
gridGap={8}
bgColor="hsla(211, 50%, 98%)"
groupGapLg={50}
groupGapSm={20}
breakpoint={800}
handleClick={this.handleClick}
selectable={true}
selectedItems={this.state.selectedItems}
handleSelection={this.handleSelection}
/>
)
}
}
8 changes: 6 additions & 2 deletions example/src/index.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
import React from 'react'
import ReactDOM from 'react-dom'
import Pig from 'pig-react'
import SelectablePig from './SelectablePig'
import imageData from './imageData.json'

import './base.css'

ReactDOM.render(
<main className="main">
{
// <SelectablePig/>
}
<Pig
imageData={imageData}
gridGap={8}
bgColor="hsla(211, 50%, 98%)"

groupGapLg={50}
groupGapSm={20}
selectable={true}
breakpoint={800}
// sortByDate
groupByDate
// groupByDate
/>
</main>
, document.getElementById('root'))
39 changes: 31 additions & 8 deletions src/components/Tile/Tile.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,15 @@ const Tile = React.memo(function Tile({
getUrl,
activeTileUrl,
handleClick,
handleSelection,
selected,
selectable,
windowHeight,
scrollSpeed,
settings,
}) {

const isSelectable = selectable
const isSelected = selected
const isExpanded = activeTileUrl === item.url
const isVideo = item.url.includes('.mp4') || item.url.includes('.mov')
const [isFullSizeLoaded, setFullSizeLoaded] = useState(isVideo ? true : false)
Expand All @@ -29,12 +33,16 @@ const Tile = React.memo(function Tile({
// screenCenter is positioning logic for when the item is active and expanded
const screenCenter = `translate3d(${offsetX}px, ${offsetY}px, 0)`

const { width, height, transform, zIndex } = useSpring({
const { width, height, transform, zIndex, marginLeft, marginRight, marginTop, marginBottom } = useSpring({
transform: isExpanded ? screenCenter : gridPosition,
zIndex: isExpanded ? 10 : 0, // 10 so that it takes a little longer before settling at 0
width: isExpanded ? Math.ceil(calcWidth) + 'px' : item.style.width + 'px',
height: isExpanded ? Math.ceil(calcHeight) + 'px' : item.style.height + 'px',
config: { mass: 1.5, tension: 400, friction: 40 }
width: isExpanded ? Math.ceil(calcWidth) + 'px' : isSelected ? item.style.width - item.style.width * 0.1 + 'px' : item.style.width + 'px',
height: isExpanded ? Math.ceil(calcHeight) + 'px' : isSelected ? item.style.height - item.style.height * 0.1 + 'px' : item.style.height + 'px',
config: { mass: 1.5, tension: 400, friction: 40 },
marginLeft: isSelected && !isExpanded ? item.style.width * 0.05 : 0,
marginRight: isSelected && !isExpanded ? item.style.width * 0.05 : 0,
marginTop: isSelected && !isExpanded ? item.style.height * 0.05 : 0,
marginBottom: isSelected && !isExpanded ? item.style.height * 0.05 : 0,
})

return (
Expand All @@ -47,7 +55,11 @@ const Tile = React.memo(function Tile({
zIndex: zIndex.interpolate(t => Math.round(t)),
width: width.interpolate(t => t),
height: height.interpolate(t => t),
transform: transform.interpolate(t => t)
transform: transform.interpolate(t => t),
marginLeft: marginLeft.interpolate(t => t),
marginRight: marginRight.interpolate(t => t),
marginTop: marginTop.interpolate(t => t),
marginBottom: marginBottom.interpolate(t => t)
}}
>

Expand All @@ -62,7 +74,7 @@ const Tile = React.memo(function Tile({
alt=""
/>
}

{(scrollSpeed === 'slow' ) && !isVideo &&
// grid image
<img
Expand Down Expand Up @@ -93,7 +105,7 @@ const Tile = React.memo(function Tile({
alt=""
/>
)}

{isExpanded && isVideo && (
// full size expanded video
<video
Expand All @@ -105,6 +117,17 @@ const Tile = React.memo(function Tile({
playsInline
/>
)}
{isSelectable && (
<input
type='checkbox'
class={styles.checkbox}
checked={isSelected}
onClick={event => {
event.stopPropagation()
handleSelection(item)
}}
></input>
)}
</animated.button>
)
})
Expand Down
25 changes: 24 additions & 1 deletion src/components/Tile/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
width: 100%;
padding: 8px;
} */
/*
/*
.caption::after {
content: '';
background-image: linear-gradient(transparent,rgba(0,0,0,.105),rgba(0,0,0,.4));
Expand All @@ -79,3 +79,26 @@
position: absolute;
z-index: -1;
} */

.pigBtn:hover .checkbox {
opacity: 0.5;
transition: all 200ms linear;
}

.pigBtn:hover .checkbox:checked {
opacity: 1;
}

.checkbox {
position: absolute;
top: 0px;
left: 0px;
opacity: 0;
}

.checkbox:checked {
position: absolute;
top: 0px;
left: 0px;
opacity: 1;
}
19 changes: 18 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ export default class Pig extends Component {

this.imageData = props.imageData

this.selectable = props.selectable || false
this.handleSelection = props.handleSelection || this.defaultHandleSelection

// if sortFunc has been provided as a prop, use it
if (props.sortFunc) this.imageData.sort(props.sortFunc)
else if (props.sortByDate) this.imageData = sortByDate(this.imageData)
Expand All @@ -44,6 +47,7 @@ export default class Pig extends Component {

this.state = {
renderedItems: [],
selectedItems: [],
scrollSpeed: 'slow',
activeTileUrl: null
}
Expand Down Expand Up @@ -95,6 +99,16 @@ export default class Pig extends Component {
this.setState({ renderedItems })
}

defaultHandleSelection = (item) => {
let newSelectedItems = this.state.selectedItems
if (newSelectedItems.includes(item)) {
newSelectedItems = newSelectedItems.filter(value => value !== item)
} else {
newSelectedItems = newSelectedItems.concat(item)
}
this.setState({selectedItems : newSelectedItems})
};

onScroll = () => {
this.previousYOffset = this.latestYOffset || window.pageYOffset
this.latestYOffset = window.pageYOffset
Expand All @@ -108,7 +122,7 @@ export default class Pig extends Component {
this.setState({ scrollSpeed }) // scroll idle callback
})
this.setState({ scrollSpeed })

// dismiss any active Tile
if (this.state.activeTileUrl) this.setState({ activeTileUrl: null })
})
Expand Down Expand Up @@ -197,6 +211,9 @@ export default class Pig extends Component {
activeTileUrl: item.url !== this.state.activeTileUrl ? item.url : null
})
}}
handleSelection={this.handleSelection}
selectable={this.selectable}
selected={this.props.selectedItems ? this.props.selectedItems.find(selectedItem => selectedItem.id === item.id) : this.state.selectedItems.includes(item)}
activeTileUrl={this.state.activeTileUrl}
settings={this.settings}
thumbnailSize={this.props.thumbnailSize}
Expand Down