mirror of
https://git.vectorsigma.ru/public/photoview.git
synced 2026-08-03 21:09:05 +00:00
Make sidebar pinable
This commit is contained in:
@@ -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>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
9
ui/src/components/sidebar/icons/pinSidebarIconFilled.svg
Normal file
9
ui/src/components/sidebar/icons/pinSidebarIconFilled.svg
Normal 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 |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
@@ -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>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user