Skip to content

Commit

Permalink
Huge change, complete rewrite tin TypeScript
Browse files Browse the repository at this point in the history
  • Loading branch information
mohitk05 committed Oct 12, 2019
0 parents commit 9a4cfe1
Show file tree
Hide file tree
Showing 18 changed files with 8,049 additions and 0 deletions.
Binary file added .DS_Store
Binary file not shown.
3 changes: 3 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"presets": ["@babel/preset-env", "@babel/preset-react"]
}
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules
dist
example
7,092 changes: 7,092 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

47 changes: 47 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"name": "react-insta-stories",
"version": "2.0.1",
"description": "A React component for Instagram like stories",
"main": "dist/index.js",
"scripts": {
"build": "rm -rf ./dist && webpack --mode production",
"build:dev": "rm -rf ./dist && webpack --mode development",
"start": "webpack-dev-server --open",
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/mohitk05/react-insta-stories.git"
},
"keywords": [
"stories",
"react",
"instagram"
],
"author": "mohitk05",
"license": "MIT",
"bugs": {
"url": "https://github.com/mohitk05/react-insta-stories/issues"
},
"homepage": "https://github.com/mohitk05/react-insta-stories#readme",
"devDependencies": {
"@babel/core": "^7.5.5",
"@babel/preset-env": "^7.5.5",
"@babel/preset-react": "^7.0.0",
"@types/react": "^16.9.2",
"@types/react-dom": "^16.8.5",
"babel-loader": "^8.0.6",
"css-loader": "^3.2.0",
"react": "^16.10.2",
"source-map-loader": "^0.2.4",
"style-loader": "^1.0.0",
"ts-loader": "^6.0.4",
"typescript": "^3.5.3",
"webpack": "^4.41.0",
"webpack-cli": "^3.3.9",
"webpack-dev-server": "^3.8.1"
},
"peerDependencies": {
"react": "^16.8.2"
}
}
110 changes: 110 additions & 0 deletions src/components/Container.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import React, { useContext, useState, useRef } from 'react'
import GlobalContext from './../context/Global'
import Story from './Story'
import ProgressArray from './ProgressArray'
import { GlobalCtx } from './../interfaces'

export default function () {
const [currentId, setCurrentId] = useState<number>(0)
const [pause, setPause] = useState<boolean>(true)
const [count, setCount] = useState<number>(0)
const [bufferAction, setBufferAction] = useState<boolean>(true)
const [videoDuration, setVideoDuration] = useState<number>(0)

let mousedownId = useRef<NodeJS.Timeout>()

const { width, height, defaultInterval, stories, loop } = useContext<GlobalCtx>(GlobalContext)

const toggleState = (action: string, bufferAction?: boolean) => {
setPause(action === 'pause')
setBufferAction(bufferAction)
}

const previous = () => {
if (currentId > 0) {
setCurrentId(currentId - 1)
setCount(0)
}
}

const next = () => {
if (loop) {
updateNextStoryIdForLoop()
} else {
updateNextStoryId()
}
};

const updateNextStoryIdForLoop = () => {
setCurrentId((currentId + 1) % stories.length)
setCount(0)
}

const updateNextStoryId = () => {
if (currentId < stories.length - 1) {
setCurrentId(currentId + 1)
setCount(0)
}
}

const debouncePause = (e: React.MouseEvent | React.TouchEvent) => {
e.preventDefault()
mousedownId.current = setTimeout(() => {
toggleState('pause')
}, 200)
}

const mouseUp = (e: React.MouseEvent | React.TouchEvent, type: string) => {
e.preventDefault()
mousedownId.current && clearTimeout(mousedownId.current)
if (pause) {
toggleState('play')
} else {
type === 'next' ? next() : previous()
}
}

const getVideoDuration = (duration: number) => {
setVideoDuration(duration)
}

return (
<div style={{ ...styles.container, ...{ width, height } }}>
<ProgressArray
next={next}
pause={pause}
bufferAction={bufferAction}
videoDuration={videoDuration}
numArray={stories.map((_, i) => i)}
currentStory={stories[currentId]}
progress={{ id: currentId }}
/>
<Story
action={toggleState}
bufferAction={bufferAction}
playState={pause}
story={stories[currentId]}
getVideoDuration={getVideoDuration}
/>
<div style={styles.overlay}>
<div style={{ width: '50%', zIndex: 999 }} onTouchStart={debouncePause} onTouchEnd={e => mouseUp(e, 'previous')} onMouseDown={debouncePause} onMouseUp={(e) => mouseUp(e, 'previous')} />
<div style={{ width: '50%', zIndex: 999 }} onTouchStart={debouncePause} onTouchEnd={e => mouseUp(e, 'next')} onMouseDown={debouncePause} onMouseUp={(e) => mouseUp(e, 'next')} />
</div>
</div>
)
}

const styles = {
container: {
display: 'flex',
flexDirection: 'column',
background: '#111',
position: 'relative'
},
overlay: {
position: 'absolute',
height: 'inherit',
width: 'inherit',
display: 'flex'
}
}
41 changes: 41 additions & 0 deletions src/components/Header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React from 'react'
import { HeaderProps } from './../interfaces'

const Header = ({ profileImage, heading, subheading }: HeaderProps) =>
<div style={styles.main}>
{profileImage && <img style={styles.img} src={profileImage} />}
<span style={styles.text}>
<p style={styles.heading}>{heading}</p>
<p style={styles.subheading}>{subheading}</p>
</span>
</div>

const styles = {
main: {
display: 'flex',
alignItems: 'center'
},
img: {
width: 40,
height: 40,
borderRadius: 40,
marginRight: 10,
filter: 'drop-shadow(0 0px 2px rgba(0, 0, 0, 0.5))',
border: '2px solid rgba(255, 255, 255, 0.8)'
},
text: {
display: 'flex',
flexDirection: 'column',
filter: 'drop-shadow(0 0px 3px rgba(0, 0, 0, 0.9))'
},
heading: {
fontSize: '1rem',
color: 'rgba(255, 255, 255, 0.9)'
},
subheading: {
fontSize: '0.6rem',
color: 'rgba(255, 255, 255, 0.8)'
}
}

export default Header
77 changes: 77 additions & 0 deletions src/components/Progress.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import React from 'react'
import { ProgressProps } from './../interfaces'
import ProgressWrapper from './ProgressWrapper'

export default class Progress extends React.PureComponent<ProgressProps, { duration: number }> {
inner: HTMLDivElement

componentDidMount() {
if (this.inner) {
this.inner.addEventListener('webkitAnimationEnd', this.next, false)
this.inner.addEventListener('animationend', this.next, false)
this.inner.addEventListener('oanimationend', this.next, false)
}
}

static getDerivedStateFromProps(props, state) {
let current = props.currentStory
if (typeof current === 'object') {
if (current.type && props.videoDuration) return { duration: props.videoDuration * 1000 }
if (current.duration) return { duration: current.duration }
return { duration: props.defaultInterval }
} else {
return { duration: props.defaultInterval }
}
}

next = () => {
this.props.next()
}

render() {
const { width, pause, bufferAction, active } = this.props
return (
<ProgressWrapper width={width} pause={pause} bufferAction={bufferAction}>
<div
ref={r => { this.inner = r }}
className={styles.inner}
style={getProgressStyle({ active, pause, duration: this.state.duration })} />
</ProgressWrapper>
)
}
}

const animation = (duration) => `${duration}ms linear 0ms ${styles.slidein}`
const animationPlayState = (pause) => pause ? 'paused' : 'running'

const getProgressStyle = ({ active, duration, pause }) => {
switch (active) {
case 2:
return { width: '100%' }
case 1:
return { animation: animation(duration), animationPlayState: animationPlayState(pause) }
case 0:
return { width: 0 }
default:
return { width: 0 }
}
}

const styles: any = {
inner: {
background: '#fff',
height: '100%',
maxWidth: '100%',
transformOrigin: 'center left',

'-webkit-backface-visibility': 'hidden',
'-moz-backface-visibility': 'hidden',
'-ms-backface-visibility': 'hidden',
backfaceVisibility: 'hidden',

'-webkit-perspective': 1000,
'-moz-perspective': 1000,
'-ms-perspective': 1000,
perspective: 1000
}
}
39 changes: 39 additions & 0 deletions src/components/ProgressArray.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React from 'react'
import Progress from './Progress'
import { ProgressArrayProps } from './../interfaces'

export default class ProgressArray extends React.Component<ProgressArrayProps> {
render() {
return (
<div style={styles.progressArr}>
{this.props.numArray.map((i, index) =>
<Progress
key={index}
width={1 / this.props.numArray.length}
next={this.props.next}
videoDuration={this.props.videoDuration}
currentStory={this.props.currentStory}
active={i === this.props.progress.id ? 1 : (i < this.props.progress.id ? 2 : 0)}
pause={this.props.pause}
bufferAction={this.props.bufferAction}
/>)}
</div>
)
}
}

const styles = {
progressArr: {
display: 'flex',
justifyContent: 'center',
maxWidth: '100%',
flexWrap: 'row',
position: 'absolute',
width: '98%',
padding: 5,
paddingTop: 7,
alignSelf: 'center',
zIndex: 99,
filter: 'drop-shadow(0 1px 8px #000)'
}
}
25 changes: 25 additions & 0 deletions src/components/ProgressWrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from 'react'
import { ProgressWrapperProps } from './../interfaces'

const ProgressWrapper = (props: ProgressWrapperProps) => (
<div style={{ ...styles.progress, ...getProgressWrapperStyle(props) }}>
{props.children}
</div>
)

const getProgressWrapperStyle = ({ width, pause, bufferAction }) => ({
width: `${width * 100}%`,
opacity: pause && !bufferAction ? 0 : 1
})

const styles = {
progress: {
height: 2,
maxWidth: '100%',
background: '#555',
margin: 2,
transition: 'opacity 400ms ease-in-out'
}
}

export default ProgressWrapper
Loading

0 comments on commit 9a4cfe1

Please sign in to comment.