Skip to content

Commit

Permalink
Added profile image lightbox;
Browse files Browse the repository at this point in the history
  • Loading branch information
stef-coenen committed Sep 5, 2023
1 parent b4704e6 commit 3b3078c
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 50 deletions.
71 changes: 71 additions & 0 deletions packages/common-app/src/dialogs/ImageLightbox/ImageLightbox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { createPortal } from 'react-dom';
import { usePortal, DialogWrapper, Times } from '@youfoundation/common-app';
import { EmbeddedThumb, TargetDrive } from '@youfoundation/js-lib/core';
import { Image } from '@youfoundation/common-app';
import { useEffect } from 'react';

export const ImageLightbox = ({
targetDrive,
fileId,
previewThumbnail,
onClose,
}: {
targetDrive: TargetDrive;
fileId: string;
previewThumbnail?: EmbeddedThumb;

onClose: () => void;
}) => {
const target = usePortal('modal-container');

useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === 'Escape') {
e.preventDefault();
e.stopPropagation();

onClose();
}
};

window.addEventListener('keydown', handleKeyDown);

return () => window.removeEventListener('keydown', handleKeyDown);
}, [onClose]);

useEffect(() => {
document.documentElement.classList.add('overflow-hidden');
return () => {
document.documentElement.classList.remove('overflow-hidden');
};
});

const dialog = (
<div className="fixed inset-0 z-50 bg-black lg:bg-transparent" role="dialog" aria-modal="true">
<div className="inset-0 bg-black transition-opacity lg:fixed"></div>
<div className="inset-0 z-10 lg:fixed lg:overflow-y-auto">
<div className="relative flex h-full min-h-screen flex-col lg:flex-row">
{onClose ? (
<button
onClick={onClose}
className="bg-secondary text-secondary-contrast absolute left-4 top-4 rounded-full p-3 hover:brightness-90 hover:filter"
>
<Times className="h-4 w-4" />
</button>
) : null}
<Image
className={`m-auto h-auto max-h-[calc(100vh-5rem)] w-auto max-w-full object-contain`}
fileId={fileId}
targetDrive={targetDrive}
alt="post"
fit="contain"
previewThumbnail={previewThumbnail}
explicitSize={'full'}
/>
</div>
</div>
</div>
);

return createPortal(dialog, target);
};
1 change: 1 addition & 0 deletions packages/common-app/src/dialogs/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './ConfirmDialog/ConfirmDialog';
export * from './InfoDialog/InfoDialog';
export * from './ImageLightbox/ImageLightbox';
14 changes: 14 additions & 0 deletions packages/common-app/src/ui/Dialog/DialogWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,20 @@ export const DialogWrapper = ({
const wrapperRef = useRef(null);
useOutsideTrigger(wrapperRef, () => !keepOpenOnBlur && onClose && onClose());

useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === 'Escape' && onClose) {
e.preventDefault();
e.stopPropagation();

!keepOpenOnBlur && onClose();
}
};

window.addEventListener('keydown', handleKeyDown);
return () => window.removeEventListener('keydown', handleKeyDown);
}, [onClose]);

useEffect(() => {
document.documentElement.classList.add('overflow-hidden');
return () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,74 +4,87 @@ import Links from '../../../../components/ui/Layout/Links/Links';
import Socials from '../../../../components/ui/Layout/Socials/Socials';
import ConnectLink from '../../../../components/ConnectionActions/ConnectLink/ConnectLink';
import FollowLink from '../../../../components/ConnectionActions/FollowLink/FollowLink';
import { OwnerName, Image, useSiteData } from '@youfoundation/common-app';
import { OwnerName, Image, useSiteData, ImageLightbox } from '@youfoundation/common-app';
import { useState } from 'react';

const ProfileHero = ({ hideLinks }: { hideLinks?: boolean }) => {
const { owner, home, social } = useSiteData().data ?? {};
const [isImageLightboxOpen, setIsImageLightboxOpen] = useState(false);

const targetDrive = GetTargetDriveFromProfileId(BuiltInProfiles.StandardProfileId);

const showProfileImage = owner?.profileImageId && targetDrive;

return (
<section className="bg-background">
<div className="relative h-[27vh] min-h-[330px]">
<Image
fileId={home?.headerImageFileId}
targetDrive={HomePageConfig.HomepageTargetDrive}
className="absolute inset-0"
fit="cover"
/>
<div className="container absolute bottom-0 left-0 right-0 top-0 mx-auto flex justify-center px-5 md:block">
<>
<section className="bg-background">
<div className="relative h-[27vh] min-h-[330px]">
<Image
fileId={home?.headerImageFileId}
targetDrive={HomePageConfig.HomepageTargetDrive}
className="absolute inset-0"
fit="cover"
/>
{showProfileImage ? (
<div className="absolute bottom-[-4.5rem] h-60 w-60 overflow-hidden rounded-full border-4 border-page-background bg-background md:bottom-[-7.5rem]">
<Image
fileId={owner?.profileImageId}
targetDrive={targetDrive}
className="h-full w-full"
fit="cover"
/>
</div>
<a onClick={() => setIsImageLightboxOpen(true)} className="cursor-pointer">
<div className="container absolute bottom-0 left-0 right-0 top-0 mx-auto flex justify-center px-5 md:block">
<div className="absolute bottom-[-4.5rem] h-60 w-60 overflow-hidden rounded-full border-4 border-page-background bg-background md:bottom-[-7.5rem]">
<Image
fileId={owner?.profileImageId}
targetDrive={targetDrive}
className="h-full w-full"
fit="cover"
/>
</div>
</div>
</a>
) : null}
</div>
</div>
{/* min height of 7.5 rem to ensure sufficient spacing after the hero picture to support the offset of the profile picture*/}
<div className="container mx-auto flex min-h-[8.5rem] px-5 xl:h-[8.5rem]">
<div className={`my-auto w-full ${showProfileImage ? 'pt-[5rem] md:py-4 md:pl-60' : ''}`}>
<div className={`flex flex-col ${showProfileImage ? 'md:pl-10' : ''} lg:flex-row`}>
<div className="text-center md:text-left">
<h1 className="text-2xl">
<OwnerName />
</h1>
<small className="block text-base">{home?.tagLine}</small>
</div>

<div className="my-3 flex flex-col justify-center md:my-auto md:ml-auto">
<div className="hidden md:contents">
<Socials
socialHandles={social}
className="mt-4 justify-center sm:mt-0 md:ml-auto md:justify-start"
/>
{/* min height of 8.5 rem to ensure sufficient spacing after the hero picture to support the offset of the profile picture*/}
<div className="container mx-auto flex min-h-[8.5rem] px-5 xl:h-[8.5rem]">
<div className={`my-auto w-full ${showProfileImage ? 'pt-[5rem] md:py-4 md:pl-60' : ''}`}>
<div className={`flex flex-col ${showProfileImage ? 'md:pl-10' : ''} lg:flex-row`}>
<div className="text-center md:text-left">
<h1 className="text-2xl">
<OwnerName />
</h1>
<small className="block text-base">{home?.tagLine}</small>
</div>

<div
className={`flex flex-row ${
!hideLinks ? 'flex-wrap' : ''
} -my-1 justify-center md:ml-4 md:mt-3`}
>
<FollowLink className="my-1 mr-3 flex-grow" />
<ConnectLink className="my-1 flex-grow" />
{!hideLinks && (
<div className="my-1">
<Links className="ml-1" direction="row" />
</div>
)}
<div className="my-3 flex flex-col justify-center md:my-auto md:ml-auto">
<div className="hidden md:contents">
<Socials
socialHandles={social}
className="mt-4 justify-center sm:mt-0 md:ml-auto md:justify-start"
/>
</div>

<div
className={`flex flex-row ${
!hideLinks ? 'flex-wrap' : ''
} -my-1 justify-center md:ml-4 md:mt-3`}
>
<FollowLink className="my-1 mr-3 flex-grow" />
<ConnectLink className="my-1 flex-grow" />
{!hideLinks && (
<div className="my-1">
<Links className="ml-1" direction="row" />
</div>
)}
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</section>
{isImageLightboxOpen && owner?.profileImageId ? (
<ImageLightbox
targetDrive={targetDrive}
fileId={owner.profileImageId}
onClose={() => setIsImageLightboxOpen(false)}
/>
) : null}
</>
);
};

Expand Down

0 comments on commit 3b3078c

Please sign in to comment.