From 91dc333eef06f60820c0732464c598c3a890a5a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20K=C3=BCndig?= Date: Thu, 4 Jan 2024 13:23:29 +0700 Subject: [PATCH] refactor(ui): make popover hoverable (#694) --- admin/src/collections/Contributions.tsx | 6 +- ui/src/components/popover.tsx | 90 +++++++++++++++---- .../(website)/(home)/(sections)/video.tsx | 18 ++-- .../src/components/navbar/navbar-client.tsx | 18 ++-- 4 files changed, 93 insertions(+), 39 deletions(-) diff --git a/admin/src/collections/Contributions.tsx b/admin/src/collections/Contributions.tsx index f23af3cad..5db8deeaf 100644 --- a/admin/src/collections/Contributions.tsx +++ b/admin/src/collections/Contributions.tsx @@ -48,9 +48,9 @@ export function buildContributionsCollection( dataType: 'string', name: 'Currency', enumValues: { - chf: 'CHF', - usd: 'USD', - eur: 'EUR', + CHF: 'CHF', + USD: 'USD', + EUR: 'EUR', }, validation: { required: true }, }, diff --git a/ui/src/components/popover.tsx b/ui/src/components/popover.tsx index 4e7a6b720..b532d0e66 100644 --- a/ui/src/components/popover.tsx +++ b/ui/src/components/popover.tsx @@ -2,30 +2,84 @@ import * as PopoverPrimitive from '@radix-ui/react-popover'; import * as React from 'react'; - +import { FC, useContext, useState } from 'react'; import { cn } from '../lib/utils'; -const Popover = PopoverPrimitive.Root; +const PopoverOnOpenChangeContext = React.createContext({ + onOpenChange: (_open: boolean) => {}, + timeoutId: { current: null } as React.MutableRefObject | null>, + openDelay: 0, + closeDelay: 200, +}); -const PopoverTrigger = PopoverPrimitive.Trigger; +const Popover: FC & { openDelay?: number; closeDelay?: number }> = ({ + open, + onOpenChange, + openDelay = 0, + closeDelay = 200, + ...props +}) => { + const [defaultOpen, defaultOnOpenChange] = useState(false); + const timeoutId = React.useRef(null); -const PopoverContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, align = 'center', sideOffset = 4, ...props }, ref) => ( - - + + + ); +}; + +const PopoverTrigger: React.FC = (props) => { + const { onOpenChange, timeoutId, openDelay, closeDelay } = useContext(PopoverOnOpenChangeContext); + + return ( + { + timeoutId.current && clearTimeout(timeoutId.current); + setTimeout(() => onOpenChange(true), openDelay); + }} + onMouseLeave={() => { + timeoutId.current = setTimeout(() => onOpenChange(false), closeDelay); + }} /> - -)); + ); +}; + +const PopoverContent = React.forwardRef< + React.ElementRef, + React.PropsWithoutRef> +>(({ align = 'center', sideOffset = 4, className, ...props }, ref) => { + const { onOpenChange, timeoutId } = useContext(PopoverOnOpenChangeContext); + + return ( + + { + timeoutId.current && clearTimeout(timeoutId.current); + }} + onMouseLeave={() => { + timeoutId.current = setTimeout(() => onOpenChange(false), 300); + }} + className={cn( + 'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 rounded-md border p-4 shadow-md outline-none', + className, + )} + {...props} + /> + + ); +}); PopoverContent.displayName = PopoverPrimitive.Content.displayName; export { Popover, PopoverContent, PopoverTrigger }; diff --git a/website/src/app/[lang]/[region]/(website)/(home)/(sections)/video.tsx b/website/src/app/[lang]/[region]/(website)/(home)/(sections)/video.tsx index e317f5726..5116fcba9 100644 --- a/website/src/app/[lang]/[region]/(website)/(home)/(sections)/video.tsx +++ b/website/src/app/[lang]/[region]/(website)/(home)/(sections)/video.tsx @@ -3,9 +3,9 @@ import { LanguageCode } from '@socialincome/shared/src/types/language'; import { Translator } from '@socialincome/shared/src/utils/i18n'; import { BaseContainer, - HoverCard, - HoverCardContent, - HoverCardTrigger, + Popover, + PopoverContent, + PopoverTrigger, Table, TableBody, TableCell, @@ -25,11 +25,11 @@ export async function Video({ lang }: { lang: LanguageCode }) {
- - + + {translator.t('video.credits-title')} - - + + {translator @@ -42,8 +42,8 @@ export async function Video({ lang }: { lang: LanguageCode }) { ))}
-
-
+ +
); diff --git a/website/src/components/navbar/navbar-client.tsx b/website/src/components/navbar/navbar-client.tsx index d7d19fa28..325302336 100644 --- a/website/src/components/navbar/navbar-client.tsx +++ b/website/src/components/navbar/navbar-client.tsx @@ -17,9 +17,9 @@ import { Collapsible, CollapsibleContent, CollapsibleTrigger, - HoverCard, - HoverCardContent, - HoverCardTrigger, + Popover, + PopoverContent, + PopoverTrigger, Typography, } from '@socialincome/ui'; import _ from 'lodash'; @@ -119,14 +119,14 @@ export function NavbarClient({ ) : ( - - + + - - + +
    {section.links?.map((link, index) => (
  • @@ -138,8 +138,8 @@ export function NavbarClient({
  • ))}
-
-
+ + )} );