Work on sidebar redesign
This commit is contained in:
parent
9d8af5bfa4
commit
4d02be1623
|
@ -4,7 +4,7 @@ import React from 'react'
|
||||||
import { Helmet } from 'react-helmet'
|
import { Helmet } from 'react-helmet'
|
||||||
import Header from '../header/Header'
|
import Header from '../header/Header'
|
||||||
import { Authorized } from '../routes/AuthorizedRoute'
|
import { Authorized } from '../routes/AuthorizedRoute'
|
||||||
import { SidebarProvider } from '../sidebar/Sidebar'
|
import { Sidebar, SidebarProvider } from '../sidebar/Sidebar'
|
||||||
import MainMenu from './MainMenu'
|
import MainMenu from './MainMenu'
|
||||||
|
|
||||||
export const ADMIN_QUERY = gql`
|
export const ADMIN_QUERY = gql`
|
||||||
|
@ -40,7 +40,7 @@ const Layout = ({ children, title, ...otherProps }: LayoutProps) => {
|
||||||
<div className="h-6"></div>
|
<div className="h-6"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* <Sidebar /> */}
|
<Sidebar />
|
||||||
</div>
|
</div>
|
||||||
</SidebarProvider>
|
</SidebarProvider>
|
||||||
)
|
)
|
||||||
|
|
|
@ -25,6 +25,7 @@ import {
|
||||||
} from './__generated__/sidebarPhoto'
|
} from './__generated__/sidebarPhoto'
|
||||||
|
|
||||||
import { sidebarDownloadQuery_media_downloads } from './__generated__/sidebarDownloadQuery'
|
import { sidebarDownloadQuery_media_downloads } from './__generated__/sidebarDownloadQuery'
|
||||||
|
import SidebarHeader from './SidebarHeader'
|
||||||
|
|
||||||
const SIDEBAR_MEDIA_QUERY = gql`
|
const SIDEBAR_MEDIA_QUERY = gql`
|
||||||
query sidebarPhoto($id: ID!) {
|
query sidebarPhoto($id: ID!) {
|
||||||
|
@ -87,13 +88,6 @@ const SIDEBAR_MEDIA_QUERY = gql`
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
const PreviewImageWrapper = styled.div<{ imageAspect: number }>`
|
|
||||||
width: 100%;
|
|
||||||
height: 0;
|
|
||||||
padding-top: ${({ imageAspect }) => Math.min(imageAspect, 0.75) * 100}%;
|
|
||||||
position: relative;
|
|
||||||
`
|
|
||||||
|
|
||||||
const PreviewImage = styled(ProtectedImage)`
|
const PreviewImage = styled(ProtectedImage)`
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -134,12 +128,6 @@ const PreviewMedia = ({ media, previewImage }: PreviewMediaProps) => {
|
||||||
return <div>ERROR: Unknown media type: {media.type}</div>
|
return <div>ERROR: Unknown media type: {media.type}</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
const Name = styled.div`
|
|
||||||
text-align: center;
|
|
||||||
font-size: 1.2rem;
|
|
||||||
margin: 0.75rem 0 1rem;
|
|
||||||
`
|
|
||||||
|
|
||||||
const MetadataInfoContainer = styled.div`
|
const MetadataInfoContainer = styled.div`
|
||||||
margin-bottom: 1.5rem;
|
margin-bottom: 1.5rem;
|
||||||
`
|
`
|
||||||
|
@ -155,7 +143,7 @@ export const MetadataInfo = ({ media }: MediaInfoProps) => {
|
||||||
const exifName = exifNameLookup(t)
|
const exifName = exifNameLookup(t)
|
||||||
|
|
||||||
if (media?.exif) {
|
if (media?.exif) {
|
||||||
const mediaExif = (media?.exif as unknown) as {
|
const mediaExif = media?.exif as unknown as {
|
||||||
[key: string]: string | number | null
|
[key: string]: string | number | null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,7 +200,7 @@ export const MetadataInfo = ({ media }: MediaInfoProps) => {
|
||||||
|
|
||||||
let videoMetadataItems: JSX.Element[] = []
|
let videoMetadataItems: JSX.Element[] = []
|
||||||
if (media?.videoMetadata) {
|
if (media?.videoMetadata) {
|
||||||
const videoMetadata = (media.videoMetadata as unknown) as {
|
const videoMetadata = media.videoMetadata as unknown as {
|
||||||
[key: string]: string | number | null
|
[key: string]: string | number | null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -371,16 +359,21 @@ const SidebarContent = ({ media, hidePreview }: SidebarContentProps) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
<SidebarHeader title={media.title ?? 'Loading...'} />
|
||||||
|
<div className="lg:mx-4">
|
||||||
{!hidePreview && (
|
{!hidePreview && (
|
||||||
<PreviewImageWrapper imageAspect={imageAspect}>
|
<div
|
||||||
|
className="w-full h-0 relative"
|
||||||
|
style={{ paddingTop: `${Math.min(imageAspect, 0.75) * 100}%` }}
|
||||||
|
>
|
||||||
<PreviewMedia
|
<PreviewMedia
|
||||||
previewImage={previewImage || undefined}
|
previewImage={previewImage || undefined}
|
||||||
media={media}
|
media={media}
|
||||||
/>
|
/>
|
||||||
<SidebarFacesOverlay media={media} />
|
<SidebarFacesOverlay media={media} />
|
||||||
</PreviewImageWrapper>
|
</div>
|
||||||
)}
|
)}
|
||||||
<Name>{media.title}</Name>
|
</div>
|
||||||
<MetadataInfo media={media} />
|
<MetadataInfo media={media} />
|
||||||
<SidebarDownload media={media} />
|
<SidebarDownload media={media} />
|
||||||
<SidebarPhotoShare id={media.id} />
|
<SidebarPhotoShare id={media.id} />
|
||||||
|
@ -418,10 +411,8 @@ type MediaSidebarType = {
|
||||||
}
|
}
|
||||||
|
|
||||||
const MediaSidebar = ({ media, hidePreview }: MediaSidebarType) => {
|
const MediaSidebar = ({ media, hidePreview }: MediaSidebarType) => {
|
||||||
const [loadMedia, { loading, error, data }] = useLazyQuery<
|
const [loadMedia, { loading, error, data }] =
|
||||||
sidebarPhoto,
|
useLazyQuery<sidebarPhoto, sidebarPhotoVariables>(SIDEBAR_MEDIA_QUERY)
|
||||||
sidebarPhotoVariables
|
|
||||||
>(SIDEBAR_MEDIA_QUERY)
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (media != null && authToken()) {
|
if (media != null && authToken()) {
|
||||||
|
|
|
@ -1,41 +1,4 @@
|
||||||
import React, { createContext, useContext, useState } from 'react'
|
import React, { createContext, useContext, useEffect, useState } from 'react'
|
||||||
import styled from 'styled-components'
|
|
||||||
import { Icon } from 'semantic-ui-react'
|
|
||||||
|
|
||||||
const SidebarContainer = styled.div<{ highlighted: boolean }>`
|
|
||||||
width: 28vw;
|
|
||||||
max-width: 500px;
|
|
||||||
min-width: 300px;
|
|
||||||
flex-shrink: 0;
|
|
||||||
overflow-y: scroll;
|
|
||||||
right: 0;
|
|
||||||
margin-top: 60px;
|
|
||||||
background-color: white;
|
|
||||||
padding: 12px;
|
|
||||||
border-left: 1px solid #eee;
|
|
||||||
|
|
||||||
@media (max-width: 700px) {
|
|
||||||
position: absolute;
|
|
||||||
width: 100%;
|
|
||||||
/* full height - header - tabbar */
|
|
||||||
height: calc(100% - 60px - 80px);
|
|
||||||
max-width: min(calc(100vw - 85px), 400px);
|
|
||||||
${({ highlighted }) => `right: ${highlighted ? 0 : -100}%;`}
|
|
||||||
padding-top: 45px;
|
|
||||||
}
|
|
||||||
|
|
||||||
transition: right 200ms ease-in-out;
|
|
||||||
`
|
|
||||||
|
|
||||||
const SidebarDismissButton = styled(Icon)`
|
|
||||||
position: absolute;
|
|
||||||
top: 10px;
|
|
||||||
right: 10px;
|
|
||||||
|
|
||||||
@media (min-width: 700px) {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
export type UpdateSidebarFn = (content: React.ReactNode) => void
|
export type UpdateSidebarFn = (content: React.ReactNode) => void
|
||||||
|
|
||||||
|
@ -78,18 +41,33 @@ export const SidebarProvider = ({ children }: SidebarProviderProps) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Sidebar = () => {
|
export const Sidebar = () => {
|
||||||
const { updateSidebar, content } = useContext(SidebarContext)
|
const { content } = useContext(SidebarContext)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const body = document.body
|
||||||
|
|
||||||
|
if (content == null) {
|
||||||
|
body.classList.remove('overflow-y-hidden')
|
||||||
|
body.classList.remove('lg:overflow-y-auto')
|
||||||
|
} else {
|
||||||
|
body.classList.add('overflow-y-hidden')
|
||||||
|
body.classList.add('lg:overflow-y-auto')
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
body.classList.remove('overflow-y-hidden')
|
||||||
|
body.classList.remove('lg:overflow-y-auto')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SidebarContainer highlighted={content != null}>
|
<div
|
||||||
|
className={`fixed top-[72px] bg-white bottom-0 w-full overflow-y-scroll transform transition-transform motion-reduce:transition-none ${
|
||||||
|
content == null ? 'translate-x-full' : 'translate-x-0'
|
||||||
|
} lg:w-[420px] lg:right-0 lg:shadow-separator lg:top-0 lg:z-40`}
|
||||||
|
>
|
||||||
{content}
|
{content}
|
||||||
<SidebarDismissButton
|
<div className="h-24"></div>
|
||||||
name="angle double right"
|
</div>
|
||||||
size="big"
|
|
||||||
link
|
|
||||||
onClick={() => updateSidebar(null)}
|
|
||||||
/>
|
|
||||||
<div style={{ height: 100 }}></div>
|
|
||||||
</SidebarContainer>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
import React, { useContext } from 'react'
|
||||||
|
|
||||||
|
import { ReactComponent as CloseIcon } from './icons/closeSidebarIcon.svg'
|
||||||
|
import { ReactComponent as PinIcon } from './icons/pinSidebarIcon.svg'
|
||||||
|
import { SidebarContext } from './Sidebar'
|
||||||
|
|
||||||
|
type SidebarHeaderProps = {
|
||||||
|
title: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const SidebarHeader = ({ title }: SidebarHeaderProps) => {
|
||||||
|
const { updateSidebar } = useContext(SidebarContext)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="m-2 flex items-center gap-2">
|
||||||
|
<button title="Close sidebar" onClick={() => updateSidebar(null)}>
|
||||||
|
<CloseIcon className="m-2" />
|
||||||
|
</button>
|
||||||
|
<span className="flex-grow -mt-1">{title}</span>
|
||||||
|
<button title="Pin sidebar">
|
||||||
|
<PinIcon className="m-2" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SidebarHeader
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="12px" height="12px" viewBox="0 0 12 12" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<path stroke="none" stroke-width="1" fill="none" d="M1,11 L11,1 M11,11 L1,1" stroke="#1F2021" stroke-width="2"></path>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 311 B |
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="16px" height="17px" viewBox="0 0 16 17" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
|
<g transform="translate(8, 8.5) rotate(-330) translate(-8, -8.5) translate(4, 2)" stroke="#1F2021">
|
||||||
|
<path d="M6.76850191,0.434840963 C6.04896114,1.86467297 5.79279384,3.20120746 6,4.44444444 C6.17989677,5.52382504 6.63266329,6.48919052 7.35829958,7.34054088 C7.50158762,7.50867286 7.48146228,7.76112984 7.31333862,7.90442763 C7.24096223,7.96611661 7.14897427,8 7.053875,8 L0.922873286,8 C0.701919553,8.00007212 0.522801161,7.82095373 0.522801161,7.59999999 C0.522801161,7.50599929 0.555900634,7.41500023 0.616293108,7.34296634 C1.36567981,6.44912577 1.82691544,5.48295181 2,4.44444444 C2.19754347,3.25918364 1.93688287,1.92116674 1.21801821,0.430393743 C1.14595115,0.281147735 1.2086138,0.10177184 1.35789863,0.0297852978 C1.39855358,0.0101811032 1.44310701,8.29112604e-18 1.4882418,0 L6.50055336,0 C6.666219,3.58349532e-05 6.80051754,0.134334371 6.80051754,0.300000012 C6.80051754,0.346829895 6.78955305,0.393009303 6.76850191,0.434840963 Z" stroke-linejoin="round"></path>
|
||||||
|
<line x1="4" y1="8" x2="4" y2="13" stroke-linecap="round"></line>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
|
@ -163,7 +163,7 @@ const TimelineGallery = () => {
|
||||||
))
|
))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div className="overflow-x-hidden">
|
||||||
<div className="mb-2">
|
<div className="mb-2">
|
||||||
<FavoritesCheckbox
|
<FavoritesCheckbox
|
||||||
onlyFavorites={onlyFavorites}
|
onlyFavorites={onlyFavorites}
|
||||||
|
@ -183,7 +183,7 @@ const TimelineGallery = () => {
|
||||||
dispatchMedia={dispatchMedia}
|
dispatchMedia={dispatchMedia}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue