diff --git a/ui/package-lock.json b/ui/package-lock.json index c996cd5f..daf62696 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -13,6 +13,7 @@ "@babel/core": "^7.14.0", "@babel/preset-react": "^7.13.13", "@babel/preset-typescript": "^7.13.0", + "@headlessui/react": "^1.2.0", "@rollup/plugin-babel": "^5.3.0", "@vitejs/plugin-react-refresh": "^1.3.3", "autoprefixer": "^10.2.5", @@ -22,6 +23,7 @@ "babel-plugin-i18next-extract": "^0.8.3", "babel-plugin-styled-components": "^1.12.0", "babel-plugin-transform-semantic-ui-react-imports": "^1.4.1", + "classnames": "^2.3.1", "connect-history-api-fallback": "^1.6.0", "copy-to-clipboard": "^3.3.1", "esbuild": "^0.11.20", @@ -1689,6 +1691,17 @@ "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.1.0.tgz", "integrity": "sha512-wYn6r8zVZyQJ6rQaALBEln5B1pzxb9shV5Ef97kTvn6yVGrqyXVnDqnU24MXnFubR+rZjBY9NWuxX3FB2sTsjg==" }, + "node_modules/@headlessui/react": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.2.0.tgz", + "integrity": "sha512-19DkLz8gDgbi+WvkoTzi9vs0NK9TJf94vbYhMzB4LYJo03Kili0gmvXT9CiKZoxXZ7YAvy/b1U1oQKEnjWrqxw==", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": ">=16" + } + }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -4493,6 +4506,11 @@ "node": ">=0.10.0" } }, + "node_modules/classnames": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz", + "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==" + }, "node_modules/clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", @@ -15007,6 +15025,12 @@ "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.1.0.tgz", "integrity": "sha512-wYn6r8zVZyQJ6rQaALBEln5B1pzxb9shV5Ef97kTvn6yVGrqyXVnDqnU24MXnFubR+rZjBY9NWuxX3FB2sTsjg==" }, + "@headlessui/react": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.2.0.tgz", + "integrity": "sha512-19DkLz8gDgbi+WvkoTzi9vs0NK9TJf94vbYhMzB4LYJo03Kili0gmvXT9CiKZoxXZ7YAvy/b1U1oQKEnjWrqxw==", + "requires": {} + }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -17179,6 +17203,11 @@ } } }, + "classnames": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz", + "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==" + }, "clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", diff --git a/ui/package.json b/ui/package.json index f517b62a..6b80fb2f 100644 --- a/ui/package.json +++ b/ui/package.json @@ -13,6 +13,7 @@ "@babel/core": "^7.14.0", "@babel/preset-react": "^7.13.13", "@babel/preset-typescript": "^7.13.0", + "@headlessui/react": "^1.2.0", "@rollup/plugin-babel": "^5.3.0", "@vitejs/plugin-react-refresh": "^1.3.3", "autoprefixer": "^10.2.5", @@ -22,6 +23,7 @@ "babel-plugin-i18next-extract": "^0.8.3", "babel-plugin-styled-components": "^1.12.0", "babel-plugin-transform-semantic-ui-react-imports": "^1.4.1", + "classnames": "^2.3.1", "connect-history-api-fallback": "^1.6.0", "copy-to-clipboard": "^3.3.1", "esbuild": "^0.11.20", diff --git a/ui/src/components/sidebar/Sharing.tsx b/ui/src/components/sidebar/Sharing.tsx index b42eedec..3cacfd0b 100644 --- a/ui/src/components/sidebar/Sharing.tsx +++ b/ui/src/components/sidebar/Sharing.tsx @@ -2,6 +2,7 @@ import React, { useEffect } from 'react' import { useMutation, useQuery, gql, useLazyQuery } from '@apollo/client' import copy from 'copy-to-clipboard' import { useTranslation } from 'react-i18next' +import { Popover } from '@headlessui/react' import { sidebareDeleteShare, sidebareDeleteShareVariables, @@ -31,6 +32,9 @@ import { ReactComponent as CopyIcon } from './icons/shareCopyIcon.svg' import { ReactComponent as DeleteIcon } from './icons/shareDeleteIcon.svg' import { ReactComponent as MoreIcon } from './icons/shareMoreIcon.svg' import { ReactComponent as AddIcon } from './icons/shareAddIcon.svg' +import Checkbox from '../../primitives/form/Checkbox' +import { TextField } from '../../primitives/form/Input' +import styled from 'styled-components' const SHARE_PHOTO_QUERY = gql` query sidebarGetPhotoShares($id: ID!) { @@ -236,6 +240,49 @@ const DELETE_SHARE_MUTATION = gql` // ) // } +const ArrowPopoverPanel = styled.div.attrs({ + className: + 'absolute right-6 -top-3 bg-white rounded shadow-md border border-gray-200 w-[260px]', +})` + &::after { + content: ''; + position: absolute; + top: 18px; + right: -7px; + width: 8px; + height: 14px; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 14'%3E%3Cpolyline stroke-width='1' stroke='%23E2E2E2' fill='%23FFFFFF' points='1 0 7 7 1 14'%3E%3C/polyline%3E%3C/svg%3E"); + } +` + +const MorePopover = () => { + const { t } = useTranslation() + + return ( + + + + + + + +
+ + +
+
+ + +
+
+
+
+ ) +} + type SidebarShareAlbumProps = { id: string } @@ -364,7 +411,7 @@ const SidebarShare = ({ const optionsRows = shares.map(share => ( - + @@ -373,9 +420,9 @@ const SidebarShare = ({ {share.token} - + - + + {/* */} @@ -405,8 +448,8 @@ const SidebarShare = ({ if (optionsRows.length == 0) { optionsRows.push( - - + + {t('sidebar.sharing.no_shares_found', 'No shares found')} @@ -419,26 +462,28 @@ const SidebarShare = ({ {t('sidebar.sharing.title', 'Sharing options')}
- - {optionsRows} - - - +
- -
+ {optionsRows} + + + + +
+ +
diff --git a/ui/src/components/sidebar/Sidebar.tsx b/ui/src/components/sidebar/Sidebar.tsx index 98c821f1..6583a702 100644 --- a/ui/src/components/sidebar/Sidebar.tsx +++ b/ui/src/components/sidebar/Sidebar.tsx @@ -38,11 +38,15 @@ export const SidebarProvider = ({ children }: SidebarProviderProps) => { pinned: boolean }>({ content: null, - pinned: false, + pinned: true, }) const updateSidebar = (content: React.ReactNode | null) => { - setState(state => ({ ...state, content })) + if (content) { + setState(state => ({ ...state, content })) + } else { + setState(state => ({ ...state, content: null, pinned: false })) + } } const setPinned = (pinned: boolean) => { @@ -88,7 +92,7 @@ export const Sidebar = () => { className={`fixed top-[72px] bg-white bottom-0 w-full overflow-y-auto transform transition-transform motion-reduce:transition-none ${ content == null && !pinned ? 'translate-x-full' : 'translate-x-0' } ${ - pinned ? 'mt-[62px]' : 'lg:shadow-separator' + pinned ? 'lg:mt-[62px]' : 'lg:shadow-separator' } lg:w-[420px] lg:right-0 lg:top-0 lg:z-40`} > {content} diff --git a/ui/src/components/sidebar/SidebarHeader.tsx b/ui/src/components/sidebar/SidebarHeader.tsx index 7768a062..291c3bb5 100644 --- a/ui/src/components/sidebar/SidebarHeader.tsx +++ b/ui/src/components/sidebar/SidebarHeader.tsx @@ -16,13 +16,19 @@ const SidebarHeader = ({ title }: SidebarHeaderProps) => { return (
- {!pinned && ( - - )} + {title} -
diff --git a/ui/src/components/sidebar/icons/shareLinkIcon.svg b/ui/src/components/sidebar/icons/shareLinkIcon.svg index 74f20a46..92932b29 100644 --- a/ui/src/components/sidebar/icons/shareLinkIcon.svg +++ b/ui/src/components/sidebar/icons/shareLinkIcon.svg @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/ui/src/components/sidebar/icons/shareMoreIcon.svg b/ui/src/components/sidebar/icons/shareMoreIcon.svg index b35c1e54..6b426ebe 100644 --- a/ui/src/components/sidebar/icons/shareMoreIcon.svg +++ b/ui/src/components/sidebar/icons/shareMoreIcon.svg @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/ui/src/primitives/form/Input.tsx b/ui/src/primitives/form/Input.tsx index ce2b14d5..2b9cad69 100644 --- a/ui/src/primitives/form/Input.tsx +++ b/ui/src/primitives/form/Input.tsx @@ -1,15 +1,20 @@ import React, { forwardRef } from 'react' +import classNames, { Argument as ClassNamesArg } from 'classnames' type TextFieldProps = { label?: string error?: string -} & React.InputHTMLAttributes + className?: ClassNamesArg + sizeVariant?: 'default' | 'small' +} & Omit, 'className'> export const TextField = forwardRef( ( - { label, error, className, ...inputProps }: TextFieldProps, + { label, error, className, sizeVariant, ...inputProps }: TextFieldProps, ref: React.ForwardedRef ) => { + sizeVariant = sizeVariant ?? 'default' + let variant = 'bg-white border-gray-200 focus:border-blue-400' if (error) variant = @@ -17,7 +22,11 @@ export const TextField = forwardRef( const input = ( @@ -28,7 +37,7 @@ export const TextField = forwardRef( if (label) { return ( - {label} @@ -39,7 +48,9 @@ export const TextField = forwardRef( } return ( -
+
{input} {errorElm}