Skip to content

Commit

Permalink
feat: ✨ add "Public activity" page
Browse files Browse the repository at this point in the history
  • Loading branch information
kitos committed Nov 26, 2018
1 parent 49f7b1a commit 7ae056c
Show file tree
Hide file tree
Showing 7 changed files with 199 additions and 19 deletions.
41 changes: 35 additions & 6 deletions gatsby-node.js
@@ -1,7 +1,36 @@
/**
* Implement Gatsby's Node APIs in this file.
*
* See: https://www.gatsbyjs.org/docs/node-apis/
*/
const crypto = require('crypto')
const axios = require('axios')

// You can delete this file if you're not using it
const { YOUTUBE_KEY } = process.env

let youtube = axios.create({
baseURL: 'https://www.googleapis.com/youtube/v3/',
params: {
key: YOUTUBE_KEY,
},
})

let videoIds = ['WXojma0u_o4', 'QLXWhxd85Lc', 'o2svfxi1Rdg']

exports.sourceNodes = async ({ actions: { createNode } }) => {
let {
data: { items: videos },
} = await youtube.get('videos', {
params: { part: 'snippet', id: videoIds.join(',') },
})

videos
.map(video => ({
...video,
parent: null,
children: [],
internal: {
type: 'YouTubeVideo',
contentDigest: crypto
.createHash(`md5`)
.update(JSON.stringify(video))
.digest(`hex`),
},
}))
.forEach(v => createNode(v))
}
31 changes: 20 additions & 11 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions package.json
Expand Up @@ -6,6 +6,7 @@
"author": "Nikita Kirsanov <kitos.kirsanov@gmail.com>",
"dependencies": {
"@rebass/grid": "^6.0.0-4",
"axios": "^0.18.0",
"babel-plugin-styled-components": "^1.8.0",
"date-fns": "^2.0.0-alpha.25",
"gatsby": "^2.0.55",
Expand All @@ -19,8 +20,8 @@
"gatsby-source-filesystem": "^2.0.8",
"gatsby-transformer-sharp": "^2.1.8",
"gatsby-transformer-yaml": "^2.1.5",
"react": "^16.6.3",
"react-dom": "^16.6.3",
"react": "^16.7.0-alpha.2",
"react-dom": "^16.7.0-alpha.2",
"react-helmet": "^5.2.0",
"react-typography": "^0.16.13",
"styled-components": "^4.1.1",
Expand Down
5 changes: 5 additions & 0 deletions src/components/header.js
Expand Up @@ -67,6 +67,11 @@ let Header = () => (
Portfolio
</MenuLink>
</li>
<li>
<MenuLink as={NavLink} to="/public-activity/">
Public activity
</MenuLink>
</li>
<li>
<MenuLink as={NavLink} to="/blog/">
Blog
Expand Down
50 changes: 50 additions & 0 deletions src/components/rotation-hook.js
@@ -0,0 +1,50 @@
import { useEffect, useRef, useState } from 'react'

export let useRotation = ({
shadowColor = 'rgba(20, 26, 40, 0.25)',
shadowK = 5,
rotationK = 7,
} = {}) => {
let initialRotation = [0, 0]
let ref = useRef(null)
let [[x, y], setPosition] = useState(initialRotation)

useEffect(() => {
let element = ref.current
let { left, top, width, height } = element.getBoundingClientRect()

let onMouseMove = e => {
let relativeX = ((e.clientX - left) / width - 0.5) * 2
let relativeY = ((e.clientY - top) / height - 0.5) * 2

setPosition([relativeX, relativeY])
}

let onMouseOut = () => {
setPosition(initialRotation)
}

element.addEventListener('mousemove', onMouseMove)
element.addEventListener('mouseout', onMouseOut)

return () => {
element.removeEventListener('mousemove', onMouseMove)
element.removeEventListener('mouseout', onMouseOut)
}
}, [])

let rotateX = `rotateX(${-y * rotationK}deg)`
let rotateY = `rotateY(${x * rotationK}deg)`

let shadowOffsetX = -x * shadowK
let shadowOffsetY = -y * shadowK

return {
ref,
style: {
willChange: 'transform',
boxShadow: `${shadowColor} ${shadowOffsetX}px ${shadowOffsetY}px 30px`,
transform: `perspective(1000px) ${rotateX} ${rotateY}`,
},
}
}
41 changes: 41 additions & 0 deletions src/components/video-card.js
@@ -0,0 +1,41 @@
import React from 'react'
import { cold } from 'react-hot-loader'
import { useRotation } from './rotation-hook'
import { scale } from '../utils/typography'
import { Box, Flex } from '@rebass/grid'
import Badge from './badge'

let VideoCard = ({ video: { id, snippet }, className }) => {
let rotation = useRotation()
let link = `https://www.youtube.com/watch?v=${id}`

return (
<section className={className}>
<a href={link} target="_blank" rel="noopener noreferrer">
<img
{...rotation}
src={snippet.thumbnails.medium.url}
alt={snippet.title}
/>
</a>

<h3 style={scale(0.1)}>
<a href={link}>{snippet.title}</a>
</h3>

{snippet.tags && (
<Flex as="ul" flexWrap="wrap" mx="-5px" css={{ listStyle: 'none' }}>
{snippet.tags.map(t => (
<Box as="li" key={t} m="5px 2px" fontSize="12px">
<Badge>#{t}</Badge>
</Box>
))}
</Flex>
)}
</section>
)
}

cold(VideoCard)

export default VideoCard
45 changes: 45 additions & 0 deletions src/pages/public-activity.js
@@ -0,0 +1,45 @@
import React from 'react'
import { graphql } from 'gatsby'
import { Box, Flex } from '@rebass/grid'

import Layout from '../components/layout'
import VideoCard from '../components/video-card'

let PublicActivityPage = ({ data: { resp: { videos = [] } = {} } = {} }) => (
<Layout>
<h2>Talks</h2>

<Flex as="ul" m={'0 -20px'} flexWrap="wrap" css={{ listStyle: 'none' }}>
{videos
.map(v => v.node)
.map(v => (
<Box as="li" key={v.id} width={[1, 'calc(50% - 20px)']} m={10}>
<VideoCard video={v} />
</Box>
))}
</Flex>
</Layout>
)

export let query = graphql`
query PublicActivityQuery {
resp: allYouTubeVideo {
videos: edges {
node {
id
snippet {
title
tags
thumbnails {
medium {
url
}
}
}
}
}
}
}
`

export default PublicActivityPage

0 comments on commit 7ae056c

Please sign in to comment.