Skip to content

Instantly share code, notes, and snippets.

@WarrenBuffering
Created June 18, 2024 03:18
Show Gist options
  • Select an option

  • Save WarrenBuffering/81bee55e16e69b035a70f6d0fa2bd097 to your computer and use it in GitHub Desktop.

Select an option

Save WarrenBuffering/81bee55e16e69b035a70f6d0fa2bd097 to your computer and use it in GitHub Desktop.

Revisions

  1. WarrenBuffering created this gist Jun 18, 2024.
    329 changes: 329 additions & 0 deletions PortfolioWork.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,329 @@
    import React, { Component } from 'react'
    import { Animated, Dimensions, Easing, PanResponder, SafeAreaView, StyleSheet, Text, View } from 'react-native'
    import { connect } from 'react-redux'
    import FastImage from 'react-native-fast-image'

    // Actions & Selectors
    import { setCurrComp, setNextComp, setPrevComp } from '../actions'
    import { getCurrComp, getNextComp, getPrevComp } from '../selectors/comps'
    import { getActiveProject } from '../selectors/projects'

    import { wait } from '../../../utils'
    import slides from '../../../json/workSlides.json'


    class WorkComps extends Component {
    screenWidth = Dimensions.get('window').width
    screenHeight = Dimensions.get('window').height

    imageWidth = this.screenWidth * .8
    imageHeight = this.imageWidth * 1.4125

    slideTransY = new Animated.Value(0)

    backgroundOpacity = new Animated.Value(1)
    slideOpacity = new Animated.Value(1)

    prevSlideZ = new Animated.Value(0)
    nextSlideZ = new Animated.Value(0)

    _handleSwipeLeft = async () => {
    await this.props.setPrevComp(0)
    await this.props.setCurrComp(0),
    await this.props.setNextComp(1)
    this.props.navigation.navigate('WorkProjects')
    }

    _handleSwipeNotCompleted = () => {
    Animated.timing(this.backgroundOpacity, {
    toValue: 1,
    duration: 200,
    easing: Easing.ease
    }).start()
    Animated.timing(this.slideOpacity, {
    toValue: 1,
    duration: 100
    }).start()
    Animated.timing(this.slideTransY, {
    toValue: 0,
    duration: 200,
    easing: Easing.bezier(.72,.35,.24,.97)
    }).start()
    }

    _panResponder = PanResponder.create({
    onStartShouldSetPanResponder: () => true,
    onPanResponderMove: (evt, { dy }) => {

    this.slideTransY.setValue((dy) * .1)

    this.backgroundOpacity.setValue( 1 - (Math.abs(dy) / this.screenHeight) * .7)
    this.slideOpacity.setValue( 1 - ((Math.abs(dy) / this.screenHeight) * 2))

    this.prevSlideZ.setValue( dy > 0 ? 99 : 9 )
    this.nextSlideZ.setValue( dy > 0 ? 9 : 99 )
    },

    onPanResponderRelease: (evt, { dx, dy, vx, vy }) => {
    const { screenHeight, screenWidth } = this
    const { currComp, activeProject } = this.props
    const comps = slides[this.props.activeProject].comps

    if (Math.abs(dx) >= screenWidth * .4) {
    if (dx > 0) {
    this._handleSwipeLeft()
    }
    } else if (currComp === 0 && dy > 0) {
    this._handleSwipeNotCompleted()
    } else if ( currComp === comps.endOfSlides && dy < 0) {
    this._handleSwipeNotCompleted()
    } else if (Math.abs(vy) >= .5 || Math.abs(dy) >= 0.2 * screenHeight) {
    if (dy > 0) {
    this._handleSwipeDownComplete(dy)
    } else if (dy < 0) {
    this._handleSwipeUpComplete(dy)
    }
    } else {
    this._handleSwipeNotCompleted()
    }
    },
    });


    _handleSwipeUpComplete = async () => {
    const { activeProject, prevComp, currComp, nextComp, setPrevComp, setCurrComp, setNextComp } = this.props
    const comps = slides[this.props.activeProject].comps
    const { endOfSlides } = comps

    if (currComp < endOfSlides) {
    setCurrComp(nextComp)
    }

    Animated.timing(this.backgroundOpacity, {
    toValue: 1,
    duration: 300,
    }).start()


    this.slideOpacity.setValue(0)
    this.slideTransY.setValue(50)

    Animated.timing(this.slideTransY, {
    toValue: 0,
    duration: 300,
    }).start()

    Animated.timing(this.slideOpacity, {
    toValue: 1,
    duration: 300
    }).start()

    await wait(300)

    let newNextComp
    if (nextComp === endOfSlides) {
    newNextComp = nextComp
    } else {
    newNextComp = nextComp + 1
    }

    setPrevComp(currComp)
    setNextComp(newNextComp)
    }


    _handleSwipeDownComplete = async () => {
    const { prevComp, currComp, nextComp, setPrevComp, setCurrComp, setNextComp } = this.props
    const comps = slides[this.props.activeProject].comps

    setCurrComp(prevComp)

    Animated.timing(this.backgroundOpacity, {
    toValue: 1,
    duration: 300,
    }).start()


    this.slideOpacity.setValue(0)
    this.slideTransY.setValue(-50)

    Animated.timing(this.slideTransY, {
    toValue: 0,
    duration: 300,
    }).start()

    Animated.timing(this.slideOpacity, {
    toValue: 1,
    duration: 300
    }).start()

    await wait(300)

    let newPrevComp
    if (prevComp === 0) {
    newPrevComp = prevComp
    } else {
    newPrevComp = prevComp - 1
    }

    setPrevComp(newPrevComp)
    setNextComp(currComp)
    }

    render() {
    const { prevComp, currComp, nextComp, activeProject } = this.props
    const { backgroundOpacity, imageHeight, imageWidth, slideTransY, nextSlideZ, prevSlideZ, screenHeight, screenWidth, slideOpacity } = this

    const themeColor = slides[activeProject].themeColor

    const comps = slides[activeProject].comps

    return (
    <View style={[styles.wrap]}>

    <Animated.View
    style={{
    backgroundColor: themeColor,
    opacity: backgroundOpacity,
    height: screenHeight,
    position: 'absolute',
    width: screenWidth,
    zIndex: prevSlideZ,
    justifyContent: 'flex-end',
    alignItems: 'center'
    }}>
    <View style={{ height: screenHeight * .6 }}>
    <FastImage
    source={{ uri: comps[prevComp].img }}
    style={[
    styles.image, {
    height: imageHeight,
    width: imageWidth
    }
    ]}
    />
    </View>
    </Animated.View>

    <Animated.View
    style={{
    backgroundColor: themeColor,
    opacity: backgroundOpacity,
    height: screenHeight,
    position: 'absolute',
    width: screenWidth,
    zIndex: nextSlideZ,
    justifyContent: 'flex-end',
    alignItems: 'center'
    }}>
    <View style={{ height: screenHeight * .6 }}>
    <FastImage
    source={{ uri: comps[nextComp].img }}
    style={[
    styles.image, {
    height: imageHeight,
    width: imageWidth
    }
    ]}
    />
    </View>
    </Animated.View>

    <Animated.View
    style={{
    backgroundColor: themeColor,
    opacity: backgroundOpacity,
    height: screenHeight,
    position: 'absolute',
    width: screenWidth,
    zIndex: 9999,
    justifyContent: 'flex-end',
    alignItems: 'center'

    }}>
    <View style={{ height: screenHeight * .6 }}>
    <FastImage
    source={{ uri: comps[currComp].img }}
    style={[
    styles.image, {
    height: imageHeight,
    width: imageWidth
    }
    ]}
    />
    </View>
    </Animated.View>

    <SafeAreaView style={styles.safeAreaView}>
    <Animated.View
    style={[
    styles.panel, {
    transform: [{
    translateY: slideTransY
    }],
    height: screenHeight,
    paddingBottom: screenHeight * .65,
    opacity: slideOpacity,
    width: screenWidth,
    }]}
    {...this._panResponder.panHandlers}
    >
    <View>
    <Text style={styles.title}>{comps[currComp].title}</Text>
    <Text style={styles.subtitle}>{comps[currComp].subtitle}</Text>
    </View>
    </Animated.View>
    </SafeAreaView>
    </View>
    )
    }
    }

    const styles = StyleSheet.create({
    wrap: {
    flex: 1,
    },
    safeAreaView: {
    height: '100%',
    position: 'absolute',
    width: '100%',
    zIndex: 99999999999,

    },
    panel: {
    justifyContent: 'flex-end',
    position: 'absolute',
    zIndex: 99999,
    paddingHorizontal: '8%'
    },
    title: {
    color: '#fff',
    fontSize: 22,
    fontFamily: 'Barlow-Bold',
    marginBottom: 14,
    textAlign: 'center',
    },
    subtitle: {
    color: '#fff',
    fontSize: 14,
    fontFamily: 'Barlow-Medium',
    lineHeight: 20,
    marginBottom: 20,
    textAlign: 'center'
    },
    })

    const mapStateToProps = state => ({
    activeProject: getActiveProject(state),
    currComp: getCurrComp(state),
    nextComp: getNextComp(state),
    prevComp: getPrevComp(state),
    })

    const mapDispatchToProps = dispatch => ({
    setCurrComp: (index) => dispatch(setCurrComp(index)),
    setNextComp: (index) => dispatch(setNextComp(index)),
    setPrevComp: (index) => dispatch(setPrevComp(index))
    })

    export default connect(mapStateToProps, mapDispatchToProps)(WorkComps)