Add right sidebar
This commit is contained in:
parent
1d5ca69701
commit
034b85e1f7
|
@ -39,6 +39,27 @@ const myAlbumQuery = function(args, ctx, info) {
|
|||
return query
|
||||
}
|
||||
|
||||
const myPhotoQuery = function(args, ctx, info) {
|
||||
const query = cypherQuery(args, ctx, info)
|
||||
|
||||
const whereSplit = query[0].indexOf('RETURN')
|
||||
|
||||
query[0] = injectAt(
|
||||
query[0],
|
||||
whereSplit,
|
||||
`MATCH (u:User { id: {userid} }) WHERE (u)-[:OWNS]->(:Album)-[:CONTAINS]->(photo) `
|
||||
)
|
||||
query[1].userid = ctx.user.id
|
||||
|
||||
query[0] = injectAt(
|
||||
query[0],
|
||||
query[0].indexOf('RETURN `photo` {') + 16,
|
||||
query[0].indexOf('RETURN `photo` {}') == -1 ? ` .id, ` : ` .id `
|
||||
)
|
||||
|
||||
return query
|
||||
}
|
||||
|
||||
const Query = {
|
||||
async myAlbums(root, args, ctx, info) {
|
||||
let query = myAlbumQuery(args, ctx, info)
|
||||
|
@ -73,6 +94,39 @@ const Query = {
|
|||
|
||||
return result.records[0].get('album')
|
||||
},
|
||||
async myPhotos(root, args, ctx, info) {
|
||||
let query = myPhotoQuery(args, ctx, info)
|
||||
console.log(query)
|
||||
|
||||
const session = ctx.driver.session()
|
||||
|
||||
const result = await session.run(...query)
|
||||
|
||||
session.close()
|
||||
|
||||
return result.records.map(record => record.get('photo'))
|
||||
},
|
||||
async photo(root, args, ctx, info) {
|
||||
const session = ctx.driver.session()
|
||||
|
||||
let query = myPhotoQuery(args, ctx, info)
|
||||
|
||||
const whereSplit = query[0].indexOf('RETURN')
|
||||
|
||||
query[0] = injectAt(query[0], whereSplit, ` AND photo.id = {id} `)
|
||||
query[1].id = args.id
|
||||
console.log(query)
|
||||
|
||||
const result = await session.run(...query)
|
||||
|
||||
session.close()
|
||||
|
||||
if (result.records.length == 0) {
|
||||
throw new Error('Album was not found')
|
||||
}
|
||||
|
||||
return result.records[0].get('photo')
|
||||
},
|
||||
}
|
||||
|
||||
function photoResolver(image) {
|
||||
|
|
|
@ -75,4 +75,7 @@ type Query {
|
|||
|
||||
myAlbums: [Album] @isAuthenticated
|
||||
album(id: ID): Album @isAuthenticated
|
||||
|
||||
myPhotos: [Photo] @isAuthenticated
|
||||
photo(id: ID): Photo @isAuthenticated
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
import React from 'react'
|
||||
import { Route, Redirect } from 'react-router-dom'
|
||||
|
||||
const AuthorizedRoute = ({ component: Component, ...props }) => {
|
||||
const token = localStorage.getItem('token')
|
||||
|
||||
let unauthorizedRedirect = null
|
||||
if (!token) {
|
||||
unauthorizedRedirect = <Redirect to="/login" />
|
||||
}
|
||||
|
||||
return (
|
||||
<Route
|
||||
{...props}
|
||||
render={routeProps => (
|
||||
<>
|
||||
{unauthorizedRedirect}
|
||||
<Component {...routeProps} />
|
||||
</>
|
||||
)}
|
||||
></Route>
|
||||
)
|
||||
}
|
||||
|
||||
export default AuthorizedRoute
|
|
@ -1,9 +1,11 @@
|
|||
import React, { Component } from 'react'
|
||||
import styled from 'styled-components'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { NavLink } from 'react-router-dom'
|
||||
import { Icon } from 'semantic-ui-react'
|
||||
|
||||
const Container = styled.div`
|
||||
height: 100%;
|
||||
margin-right: 500px;
|
||||
/* display: grid;
|
||||
grid-template-columns: 80px 1fr 500px; */
|
||||
`
|
||||
|
@ -17,31 +19,42 @@ const LeftSidebar = styled.div`
|
|||
padding-top: 10px;
|
||||
`
|
||||
|
||||
const RightSidebar = styled.div`
|
||||
height: 100%;
|
||||
width: 500px;
|
||||
position: fixed;
|
||||
right: 0;
|
||||
top: 60px;
|
||||
background-color: white;
|
||||
`
|
||||
|
||||
const Content = styled.div`
|
||||
margin-top: 60px;
|
||||
margin-left: 80px;
|
||||
margin-right: 500px;
|
||||
padding: 12px 8px 0;
|
||||
`
|
||||
|
||||
const SideButton = styled(Link)`
|
||||
border: 1px solid #eee;
|
||||
const SideButton = props => {
|
||||
const StyledLink = styled(NavLink)`
|
||||
text-align: center;
|
||||
padding-top: 17px;
|
||||
border-radius: 50%;
|
||||
padding-top: 8px;
|
||||
padding-left: 2px;
|
||||
display: block;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
margin: 10px;
|
||||
|
||||
font-size: 28px;
|
||||
|
||||
color: #888;
|
||||
|
||||
transition: transform 200ms, box-shadow 200ms;
|
||||
|
||||
:hover {
|
||||
transform: scale(1.02);
|
||||
}
|
||||
`
|
||||
|
||||
return (
|
||||
<StyledLink {...props} activeStyle={{ color: '#4183c4' }}>
|
||||
{props.children}
|
||||
</StyledLink>
|
||||
)
|
||||
}
|
||||
|
||||
const SideButtonLabel = styled.div`
|
||||
font-size: 16px;
|
||||
`
|
||||
|
||||
const Header = styled.div`
|
||||
|
@ -64,10 +77,12 @@ class Layout extends Component {
|
|||
return (
|
||||
<Container>
|
||||
<LeftSidebar>
|
||||
<SideButton to="/">Albums</SideButton>
|
||||
<SideButton to="/" exact>
|
||||
<Icon name="images outline" />
|
||||
<SideButtonLabel>Albums</SideButtonLabel>
|
||||
</SideButton>
|
||||
</LeftSidebar>
|
||||
<Content>{this.props.children}</Content>
|
||||
<RightSidebar>Right</RightSidebar>
|
||||
<Header>
|
||||
<Title>Photoview</Title>
|
||||
</Header>
|
||||
|
|
|
@ -1,8 +1,16 @@
|
|||
import React, { Component } from 'react'
|
||||
import gql from 'graphql-tag'
|
||||
import { Query } from 'react-apollo'
|
||||
import { Gallery, Photo, PhotoFiller } from './styledElements'
|
||||
import {
|
||||
Gallery,
|
||||
Photo,
|
||||
PhotoFiller,
|
||||
PhotoContainer,
|
||||
PhotoOverlay,
|
||||
} from './styledElements'
|
||||
import Layout from '../../Layout'
|
||||
import { Loader } from 'semantic-ui-react'
|
||||
import AlbumSidebar from './AlbumSidebar'
|
||||
|
||||
const albumQuery = gql`
|
||||
query albumQuery($id: ID) {
|
||||
|
@ -33,7 +41,7 @@ class AlbumPage extends Component {
|
|||
this.photoAmount = 1
|
||||
this.previousActive = false
|
||||
|
||||
this.keyUpEvent = e => {
|
||||
this.keyDownEvent = e => {
|
||||
const activeImage = this.state.activeImage
|
||||
if (activeImage != -1) {
|
||||
if (e.key == 'ArrowRight') {
|
||||
|
@ -52,11 +60,11 @@ class AlbumPage extends Component {
|
|||
}
|
||||
|
||||
componentDidMount() {
|
||||
document.addEventListener('keyup', this.keyUpEvent)
|
||||
document.addEventListener('keydown', this.keyDownEvent)
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
document.removeEventListener('keyup', this.keyUpEvent)
|
||||
document.removeEventListener('keydown', this.keyDownEvent)
|
||||
}
|
||||
|
||||
setActiveImage(index) {
|
||||
|
@ -80,23 +88,45 @@ class AlbumPage extends Component {
|
|||
<Query query={albumQuery} variables={{ id: albumId }}>
|
||||
{({ loading, error, data }) => {
|
||||
if (error) return <div>Error</div>
|
||||
if (loading) return <div>Loading</div>
|
||||
|
||||
let photos = null
|
||||
if (data.album) {
|
||||
this.photoAmount = data.album.photos.length
|
||||
|
||||
const { activeImage } = this.state
|
||||
|
||||
const photos = data.album.photos.map((photo, index) => {
|
||||
return <Photo key={photo.id} src={photo.thumbnail.path}></Photo>
|
||||
photos = data.album.photos.map((photo, index) => {
|
||||
const active = activeImage == index
|
||||
|
||||
return (
|
||||
<PhotoContainer
|
||||
key={photo.id}
|
||||
onClick={() => {
|
||||
this.setActiveImage(index)
|
||||
}}
|
||||
>
|
||||
<Photo src={photo.thumbnail.path} />
|
||||
<PhotoOverlay active={active} />
|
||||
</PhotoContainer>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>{data.album.title}</h1>
|
||||
<h1>{data.album ? data.album.title : ''}</h1>
|
||||
<Gallery>
|
||||
<Loader active={loading}>Loading images</Loader>
|
||||
{photos}
|
||||
<PhotoFiller />
|
||||
</Gallery>
|
||||
<AlbumSidebar
|
||||
imageId={
|
||||
this.state.activeImage != -1
|
||||
? data.album.photos[this.state.activeImage].id
|
||||
: null
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
import React, { Component } from 'react'
|
||||
import styled from 'styled-components'
|
||||
import { Query } from 'react-apollo'
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
const photoQuery = gql`
|
||||
query sidebarPhoto($id: ID) {
|
||||
photo(id: $id) {
|
||||
title
|
||||
original {
|
||||
path
|
||||
width
|
||||
height
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const RightSidebar = styled.div`
|
||||
height: 100%;
|
||||
width: 500px;
|
||||
position: fixed;
|
||||
right: 0;
|
||||
top: 60px;
|
||||
background-color: white;
|
||||
padding: 12px;
|
||||
border-left: 1px solid #eee;
|
||||
`
|
||||
|
||||
const PreviewImage = styled.img`
|
||||
width: 100%;
|
||||
height: 333px;
|
||||
object-fit: contain;
|
||||
`
|
||||
|
||||
const Name = styled.div`
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
`
|
||||
|
||||
class AlbumSidebar extends Component {
|
||||
render() {
|
||||
const { imageId } = this.props
|
||||
|
||||
if (!imageId) {
|
||||
return <RightSidebar />
|
||||
}
|
||||
|
||||
return (
|
||||
<RightSidebar>
|
||||
<Query query={photoQuery} variables={{ id: imageId }}>
|
||||
{({ loading, error, data }) => {
|
||||
if (loading) return 'Loading...'
|
||||
if (error) return error
|
||||
|
||||
const { photo } = data
|
||||
|
||||
return (
|
||||
<div>
|
||||
<PreviewImage src={photo.original.path} />
|
||||
<Name>{photo.title}</Name>
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
</Query>
|
||||
</RightSidebar>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default AlbumSidebar
|
|
@ -6,19 +6,32 @@ export const Gallery = styled.div`
|
|||
align-items: center;
|
||||
`
|
||||
|
||||
export const Photo = styled.img`
|
||||
export const PhotoContainer = styled.div`
|
||||
flex-grow: 1;
|
||||
height: 200px;
|
||||
margin: 4px;
|
||||
background-color: #eee;
|
||||
position: relative;
|
||||
`
|
||||
|
||||
export const Photo = styled.img`
|
||||
height: 200px;
|
||||
flex-grow: 1;
|
||||
min-width: 100%;
|
||||
position: relative;
|
||||
object-fit: cover;
|
||||
`
|
||||
|
||||
export const PhotoOverlay = styled.div`
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
${props =>
|
||||
props.active &&
|
||||
`
|
||||
will-change: transform;
|
||||
position: relative;
|
||||
z-index: 999;
|
||||
border: 4px solid rgba(65, 131, 196, 0.6);
|
||||
`}
|
||||
`
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ import gql from 'graphql-tag'
|
|||
import { Query } from 'react-apollo'
|
||||
import styled from 'styled-components'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { Dimmer, Loader } from 'semantic-ui-react'
|
||||
import { Loader } from 'semantic-ui-react'
|
||||
|
||||
const getAlbumsQuery = gql`
|
||||
query getMyAlbums {
|
||||
|
|
|
@ -4,22 +4,15 @@ import { Route, Switch } from 'react-router-dom'
|
|||
import LoginPage from './Pages/LoginPage'
|
||||
import HomePage from './Pages/HomePage/HomePage'
|
||||
import AlbumPage from './Pages/AlbumPage/AlbumPage'
|
||||
import AuthorizedRoute from './AuthorizedRoute'
|
||||
|
||||
class Routes extends Component {
|
||||
render() {
|
||||
const token = localStorage.getItem('token')
|
||||
|
||||
let unauthorizedRedirect = null
|
||||
if (!token) {
|
||||
unauthorizedRedirect = <Redirect to="/login" />
|
||||
}
|
||||
|
||||
return (
|
||||
<Switch>
|
||||
{unauthorizedRedirect}
|
||||
<Route path="/login" component={LoginPage} />
|
||||
<Route exact path="/" component={HomePage} />
|
||||
<Route path="/album/:id" component={AlbumPage} />
|
||||
<AuthorizedRoute exact path="/" component={HomePage} />
|
||||
<AuthorizedRoute path="/album/:id" component={AlbumPage} />
|
||||
</Switch>
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue