Start on timeline frontend
This commit is contained in:
parent
214c4e8be4
commit
9c84336d34
|
@ -5,6 +5,11 @@ import Routes from './components/routes/Routes'
|
||||||
import Messages from './components/messages/Messages'
|
import Messages from './components/messages/Messages'
|
||||||
|
|
||||||
const GlobalStyle = createGlobalStyle`
|
const GlobalStyle = createGlobalStyle`
|
||||||
|
* {
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import Layout from '../../Layout'
|
import Layout from '../../Layout'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import GalleryGroups from '../../components/photoGallery/GalleryGroups'
|
import TimelineGallery from '../../components/timelineGallery/TimelineGallery'
|
||||||
|
|
||||||
const PhotosPage = ({ match }) => {
|
const PhotosPage = () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Layout title="Photos">
|
<Layout title="Photos">
|
||||||
<GalleryGroups subPage={match.params.subPage} />
|
<TimelineGallery />
|
||||||
</Layout>
|
</Layout>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|
|
@ -122,7 +122,6 @@ const VideoThumbnailIcon = styled(Icon)`
|
||||||
export const MediaThumbnail = ({
|
export const MediaThumbnail = ({
|
||||||
media,
|
media,
|
||||||
onSelectImage,
|
onSelectImage,
|
||||||
minWidth,
|
|
||||||
index,
|
index,
|
||||||
active,
|
active,
|
||||||
setPresenting,
|
setPresenting,
|
||||||
|
@ -163,6 +162,13 @@ export const MediaThumbnail = ({
|
||||||
videoIcon = <VideoThumbnailIcon name="play" size="big" />
|
videoIcon = <VideoThumbnailIcon name="play" size="big" />
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let minWidth = 100
|
||||||
|
if (media.thumbnail) {
|
||||||
|
minWidth = Math.floor(
|
||||||
|
(media.thumbnail.width / media.thumbnail.height) * 200
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MediaContainer
|
<MediaContainer
|
||||||
key={media.id}
|
key={media.id}
|
||||||
|
@ -173,8 +179,15 @@ export const MediaThumbnail = ({
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
onSelectImage && onSelectImage(index)
|
onSelectImage && onSelectImage(index)
|
||||||
}}
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
minWidth: `${minWidth}px`,
|
||||||
|
height: `200px`,
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<LazyPhoto src={media.thumbnail && media.thumbnail.url} />
|
<LazyPhoto src={media.thumbnail && media.thumbnail.url} />
|
||||||
|
</div>
|
||||||
<PhotoOverlay active={active}>
|
<PhotoOverlay active={active}>
|
||||||
{videoIcon}
|
{videoIcon}
|
||||||
<HoverIcon
|
<HoverIcon
|
||||||
|
|
|
@ -54,13 +54,6 @@ const PhotoGallery = ({
|
||||||
photoElements = media.map((photo, index) => {
|
photoElements = media.map((photo, index) => {
|
||||||
const active = activeIndex == index
|
const active = activeIndex == index
|
||||||
|
|
||||||
let minWidth = 100
|
|
||||||
if (photo.thumbnail) {
|
|
||||||
minWidth = Math.floor(
|
|
||||||
(photo.thumbnail.width / photo.thumbnail.height) * 200
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MediaThumbnail
|
<MediaThumbnail
|
||||||
key={photo.id}
|
key={photo.id}
|
||||||
|
@ -71,7 +64,6 @@ const PhotoGallery = ({
|
||||||
}}
|
}}
|
||||||
onFavorite={onFavorite}
|
onFavorite={onFavorite}
|
||||||
setPresenting={setPresenting}
|
setPresenting={setPresenting}
|
||||||
minWidth={minWidth}
|
|
||||||
index={index}
|
index={index}
|
||||||
active={active}
|
active={active}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
import React from 'react'
|
||||||
|
import { useQuery, gql } from '@apollo/client'
|
||||||
|
import TimelineGroupDate from './TimelineGroupDate'
|
||||||
|
import styled from 'styled-components'
|
||||||
|
|
||||||
|
const MY_TIMELINE_QUERY = gql`
|
||||||
|
query myTimeline {
|
||||||
|
myTimeline {
|
||||||
|
album {
|
||||||
|
id
|
||||||
|
title
|
||||||
|
}
|
||||||
|
media {
|
||||||
|
id
|
||||||
|
thumbnail {
|
||||||
|
url
|
||||||
|
width
|
||||||
|
height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mediaTotal
|
||||||
|
date
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const GalleryWrapper = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
`
|
||||||
|
|
||||||
|
const TimelineGallery = () => {
|
||||||
|
const { data, error } = useQuery(MY_TIMELINE_QUERY)
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return error
|
||||||
|
}
|
||||||
|
|
||||||
|
let timelineGroups = null
|
||||||
|
if (data?.myTimeline) {
|
||||||
|
const dateGroupedAlbums = data.myTimeline.reduce((acc, val) => {
|
||||||
|
if (acc.length == 0 || acc[acc.length - 1].date != val.date) {
|
||||||
|
acc.push({
|
||||||
|
date: val.date,
|
||||||
|
groups: [val],
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
acc[acc.length - 1].groups.push(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
timelineGroups = dateGroupedAlbums.map(({ date, groups }) => (
|
||||||
|
<TimelineGroupDate key={date} date={date} groups={groups} />
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
return <GalleryWrapper>{timelineGroups}</GalleryWrapper>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TimelineGallery
|
|
@ -0,0 +1,61 @@
|
||||||
|
import React from 'react'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import { MediaThumbnail } from '../photoGallery/MediaThumbnail'
|
||||||
|
import styled from 'styled-components'
|
||||||
|
|
||||||
|
const MediaWrapper = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
height: 200px;
|
||||||
|
position: relative;
|
||||||
|
margin: -4px;
|
||||||
|
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
@media (max-width: 1000px) {
|
||||||
|
/* Compensate for tab bar on mobile */
|
||||||
|
margin-bottom: 76px;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const AlbumTitle = styled.h2`
|
||||||
|
color: #212121;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
font-weight: 200;
|
||||||
|
margin: 0 0 4px;
|
||||||
|
`
|
||||||
|
|
||||||
|
const GroupAlbumWrapper = styled.div`
|
||||||
|
margin-top: 12px;
|
||||||
|
`
|
||||||
|
|
||||||
|
const TimelineGroupAlbum = ({ group: { album, media /* mediaTotal */ } }) => {
|
||||||
|
const mediaElms = media.map(media => (
|
||||||
|
<MediaThumbnail
|
||||||
|
key={media.id}
|
||||||
|
media={media}
|
||||||
|
onSelectImage={() => {
|
||||||
|
// todo
|
||||||
|
}}
|
||||||
|
setPresenting={() => {
|
||||||
|
// todo
|
||||||
|
}}
|
||||||
|
index={0}
|
||||||
|
active={false}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
|
||||||
|
return (
|
||||||
|
<GroupAlbumWrapper>
|
||||||
|
<AlbumTitle>{album.title}</AlbumTitle>
|
||||||
|
<MediaWrapper>{mediaElms}</MediaWrapper>
|
||||||
|
</GroupAlbumWrapper>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
TimelineGroupAlbum.propTypes = {
|
||||||
|
group: PropTypes.object.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TimelineGroupAlbum
|
|
@ -0,0 +1,41 @@
|
||||||
|
import React from 'react'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import TimelineGroupAlbum from './TimelineGroupAlbum'
|
||||||
|
import styled from 'styled-components'
|
||||||
|
|
||||||
|
const dateFormatter = new Intl.DateTimeFormat(navigator.language, {
|
||||||
|
year: 'numeric',
|
||||||
|
month: 'long',
|
||||||
|
day: 'numeric',
|
||||||
|
})
|
||||||
|
|
||||||
|
const GroupDateWrapper = styled.div`
|
||||||
|
margin: 12px 12px;
|
||||||
|
`
|
||||||
|
|
||||||
|
const DateTitle = styled.h1`
|
||||||
|
font-size: 1.5rem;
|
||||||
|
margin: 0 0 -12px;
|
||||||
|
`
|
||||||
|
|
||||||
|
const TimelineGroupDate = ({ date, groups }) => {
|
||||||
|
const groupElms = groups.map(group => (
|
||||||
|
<TimelineGroupAlbum key={`${group.date}_${group.album.id}`} group={group} />
|
||||||
|
))
|
||||||
|
|
||||||
|
const formattedDate = dateFormatter.format(new Date(date))
|
||||||
|
|
||||||
|
return (
|
||||||
|
<GroupDateWrapper>
|
||||||
|
<DateTitle>{formattedDate}</DateTitle>
|
||||||
|
<div>{groupElms}</div>
|
||||||
|
</GroupDateWrapper>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
TimelineGroupDate.propTypes = {
|
||||||
|
date: PropTypes.string.isRequired,
|
||||||
|
groups: PropTypes.array.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TimelineGroupDate
|
Loading…
Reference in New Issue