1
Fork 0

Add right sidebar

This commit is contained in:
viktorstrate 2019-07-19 21:39:51 +02:00
parent 1d5ca69701
commit 034b85e1f7
9 changed files with 253 additions and 49 deletions

View File

@ -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) {

View File

@ -75,4 +75,7 @@ type Query {
myAlbums: [Album] @isAuthenticated
album(id: ID): Album @isAuthenticated
myPhotos: [Photo] @isAuthenticated
photo(id: ID): Photo @isAuthenticated
}

25
ui/src/AuthorizedRoute.js Normal file
View File

@ -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

View File

@ -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>

View File

@ -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>
)
}}

View File

@ -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

View File

@ -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);
`}
`

View File

@ -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 {

View File

@ -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>
)
}