Make sidebar pinable

This commit is contained in:
viktorstrate
2021-06-02 19:11:56 +02:00
parent 4d02be1623
commit 0b386ca205
6 changed files with 65 additions and 19 deletions

View File

@@ -1,10 +1,10 @@
import { gql } from '@apollo/client'
import PropTypes from 'prop-types'
import React from 'react'
import React, { useContext } from 'react'
import { Helmet } from 'react-helmet'
import Header from '../header/Header'
import { Authorized } from '../routes/AuthorizedRoute'
import { Sidebar, SidebarProvider } from '../sidebar/Sidebar'
import { Sidebar, SidebarContext } from '../sidebar/Sidebar'
import MainMenu from './MainMenu'
export const ADMIN_QUERY = gql`
@@ -21,8 +21,10 @@ type LayoutProps = {
}
const Layout = ({ children, title, ...otherProps }: LayoutProps) => {
const { pinned, content: sidebarContent } = useContext(SidebarContext)
return (
<SidebarProvider>
<>
<Helmet>
<title>{title ? `${title} - Photoview` : `Photoview`}</title>
</Helmet>
@@ -33,7 +35,9 @@ const Layout = ({ children, title, ...otherProps }: LayoutProps) => {
<MainMenu />
</Authorized>
<div
className="px-3 py-3 lg:pt-5 lg:pr-8 lg:pl-[292px]"
className={`px-3 py-3 lg:pt-5 lg:pr-8 lg:pl-[292px] ${
pinned && sidebarContent ? 'lg:pr-[420px]' : ''
}`}
id="layout-content"
>
{children}
@@ -42,7 +46,7 @@ const Layout = ({ children, title, ...otherProps }: LayoutProps) => {
</div>
<Sidebar />
</div>
</SidebarProvider>
</>
)
}

View File

@@ -1,10 +1,13 @@
import React, { createContext, useContext, useEffect, useState } from 'react'
export type UpdateSidebarFn = (content: React.ReactNode) => void
export type SidebarPinnedFn = (pin: boolean) => void
interface SidebarContextType {
updateSidebar: UpdateSidebarFn
setPinned: SidebarPinnedFn
content: React.ReactNode
pinned: boolean
}
export const SidebarContext = createContext<SidebarContextType>({
@@ -14,7 +17,14 @@ export const SidebarContext = createContext<SidebarContextType>({
content
)
},
setPinned: content => {
console.warn(
'SidebarContext: setPinned was called before initialized',
content
)
},
content: null,
pinned: false,
})
SidebarContext.displayName = 'SidebarContext'
@@ -23,17 +33,30 @@ type SidebarProviderProps = {
}
export const SidebarProvider = ({ children }: SidebarProviderProps) => {
const [state, setState] = useState<{ content: React.ReactNode | null }>({
const [state, setState] = useState<{
content: React.ReactNode | null
pinned: boolean
}>({
content: null,
pinned: false,
})
const update = (content: React.ReactNode | null) => {
setState({ content })
const updateSidebar = (content: React.ReactNode | null) => {
setState(state => ({ ...state, content }))
}
const setPinned = (pinned: boolean) => {
setState(state => ({ ...state, pinned }))
}
return (
<SidebarContext.Provider
value={{ updateSidebar: update, content: state.content }}
value={{
updateSidebar,
setPinned,
content: state.content,
pinned: state.pinned,
}}
>
{children}
</SidebarContext.Provider>
@@ -41,7 +64,7 @@ export const SidebarProvider = ({ children }: SidebarProviderProps) => {
}
export const Sidebar = () => {
const { content } = useContext(SidebarContext)
const { content, pinned } = useContext(SidebarContext)
useEffect(() => {
const body = document.body
@@ -63,8 +86,10 @@ export const Sidebar = () => {
return (
<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 == null && !pinned ? 'translate-x-full' : 'translate-x-0'
} ${
pinned ? 'mt-[62px]' : 'lg:shadow-separator'
} lg:w-[420px] lg:right-0 lg:top-0 lg:z-40`}
>
{content}
<div className="h-24"></div>

View File

@@ -1,7 +1,8 @@
import React, { useContext } from 'react'
import { ReactComponent as CloseIcon } from './icons/closeSidebarIcon.svg'
import { ReactComponent as PinIcon } from './icons/pinSidebarIcon.svg'
import { ReactComponent as PinIconOutline } from './icons/pinSidebarIconOutline.svg'
import { ReactComponent as PinIconFilled } from './icons/pinSidebarIconFilled.svg'
import { SidebarContext } from './Sidebar'
type SidebarHeaderProps = {
@@ -9,15 +10,19 @@ type SidebarHeaderProps = {
}
const SidebarHeader = ({ title }: SidebarHeaderProps) => {
const { updateSidebar } = useContext(SidebarContext)
const { updateSidebar, setPinned, pinned } = useContext(SidebarContext)
const PinIcon = pinned ? PinIconFilled : PinIconOutline
return (
<div className="m-2 flex items-center gap-2">
<button title="Close sidebar" onClick={() => updateSidebar(null)}>
<CloseIcon className="m-2" />
</button>
{!pinned && (
<button title="Close sidebar" onClick={() => updateSidebar(null)}>
<CloseIcon className="m-2" />
</button>
)}
<span className="flex-grow -mt-1">{title}</span>
<button title="Pin sidebar">
<button title="Pin sidebar" onClick={() => setPinned(!pinned)}>
<PinIcon className="m-2" />
</button>
</div>

View File

@@ -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" fill="#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

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -10,13 +10,16 @@ import { BrowserRouter as Router } from 'react-router-dom'
import { setupLocalization } from './localization'
import './index.css'
import { SidebarProvider } from './components/sidebar/Sidebar'
setupLocalization()
const Main = () => (
<ApolloProvider client={client}>
<Router>
<App />
<SidebarProvider>
<App />
</SidebarProvider>
</Router>
</ApolloProvider>
)