Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update side panels to allow drawer experience #691

Merged
merged 2 commits into from
Nov 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export function ModalNextUiAdapter<C extends ElementType = "div">({
classNames={{
base: cn(slots.modal(), classNames?.modal),
body: cn(slots.body(), classNames?.body),
wrapper: "overflow-hidden p-[5%]",
wrapper: "overflow-hidden p-[5%] z-[999]",
backdrop: cn(slots.backdrop(), classNames?.backdrop),
header: cn(slots.header(), classNames?.header),
footer: cn(slots.footer(), classNames?.footer),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { cn } from "@/shared/helpers/cn";
export const ModalNextUiVariants = tv({
slots: {
modal:
"group !mx-0 !my-0 flex max-h-full max-w-full flex-col gap-lg overflow-hidden rounded-xl border border-border-primary bg-background-primary-alt",
"group z-[999] !mx-0 !my-0 flex max-h-full max-w-full flex-col gap-lg overflow-hidden rounded-xl border border-border-primary bg-background-primary-alt",
wrapper: "flex flex-1 flex-col overflow-hidden",
body: "overflow-hidden !p-3xl",
backdrop: "bg-background-overlay",
Expand Down
36 changes: 30 additions & 6 deletions shared/features/side-panels/side-panel/side-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ import {
useState,
} from "react";
import { createPortal } from "react-dom";
import { useDebounce } from "react-use";

import { AnyType } from "@/core/kernel/types";

import { Paper } from "@/design-system/atoms/paper";

import { useSidePanelsContext } from "@/shared/features/side-panels/side-panels.context";
import { SIDE_PANEL_ANIMATION_DURATION, useSidePanelsContext } from "@/shared/features/side-panels/side-panels.context";
import { SidePanelConfig } from "@/shared/features/side-panels/side-panels.types";
import { cn } from "@/shared/helpers/cn";
import { useIsTablet } from "@/shared/hooks/ui/use-media-query";
Expand All @@ -32,9 +33,19 @@ export const SidePanel = forwardRef(function SidePanel<T extends AnyType>(
const { open, close, container, isOpen, isOpenLast, getPanelIndex, getConfig, back, openedPanels, getData } =
useSidePanelsContext();

const [showContent, setShowContent] = useState(false);
const [debouncedShowContent, setDebouncedShowContent] = useState(false);
const isTablet = useIsTablet("lower");
const panelConfig = getConfig(name);

useDebounce(
() => {
setDebouncedShowContent(showContent);
},
SIDE_PANEL_ANIMATION_DURATION * 1000,
[showContent]
);

const animate: Variants = {
isClosed: { transform: "translateX(100%)", opacity: 0 },
isOpen: { transform: "translateX(0%)", opacity: 1 },
Expand All @@ -60,12 +71,21 @@ export const SidePanel = forwardRef(function SidePanel<T extends AnyType>(
const animateKey = isOpenLast(name) ? "isOpen" : "isClosed";

const panelContent = useMemo(() => {
if (openedPanels.length && isOpen(name)) {
if (debouncedShowContent) {
return children;
}

return null;
}, [openedPanels, isOpen, name, children]);
}, [debouncedShowContent, children]);

useEffect(() => {
if (openedPanels.length && isOpen(name)) {
setShowContent(true);
setDebouncedShowContent(true);
} else {
setShowContent(false);
}
}, [openedPanels, isOpen, name]);

return (
<>
Expand All @@ -79,10 +99,10 @@ export const SidePanel = forwardRef(function SidePanel<T extends AnyType>(
<motion.div
variants={isTablet ? animateTablet : animate}
animate={animateKey}
transition={{ type: "ease", duration: 0.25 }}
transition={{ type: "ease", duration: SIDE_PANEL_ANIMATION_DURATION }}
initial={false}
className={cn(
"absolute right-0 translate-x-full opacity-0",
"absolute right-0 translate-x-full overflow-hidden opacity-0",
{ "top-0 h-full translate-x-full": !isTablet },
{ "fixed bottom-0 h-[calc(100%_-_64px)] translate-y-full p-md": isTablet },
{ invisible: !isOpenLast(name) },
Expand All @@ -91,7 +111,7 @@ export const SidePanel = forwardRef(function SidePanel<T extends AnyType>(
style={{
minWidth: isTablet ? "100%" : `${panelConfig.width}rem`,
width: isTablet ? "100%" : `${panelConfig.width}rem`,
zIndex: getPanelIndex(name),
zIndex: getPanelIndex(name) ?? 1,
}}
>
<Paper
Expand All @@ -102,6 +122,10 @@ export const SidePanel = forwardRef(function SidePanel<T extends AnyType>(
classNames={{
base: cn(
"h-full w-full flex flex-col gap-px overflow-hidden",
{
"border-l-border-primary !border-l !border-solid effect-box-shadow-sm rounded-l-none":
panelConfig.type === "drawer",
},
{ "max-h-dvh": isTablet },
classNames?.content
),
Expand Down
28 changes: 23 additions & 5 deletions shared/features/side-panels/side-panels.context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@ const defaultConfig: SidePanelConfig = {
width: SIDE_PANEL_SIZE.m,
gap: SIDE_PANEL_GAP.m,
closedWidth: 0,
type: "drawer",
};

export const SIDE_PANEL_ANIMATION_DURATION = 0.25;

export const SidePanelsContext = createContext<SidePanelsContextInterface>({
isOpen: () => false,
open: () => {},
Expand All @@ -47,6 +50,7 @@ export function SidePanelsProvider({ children, classNames }: SidePanelsContextPr
width: config.width ?? defaultConfig.width,
gap: config.gap ?? defaultConfig.gap,
closedWidth: config.closedWidth ?? defaultConfig.closedWidth,
type: config.type ?? defaultConfig.type,
};
}

Expand Down Expand Up @@ -93,8 +97,11 @@ export function SidePanelsProvider({ children, classNames }: SidePanelsContextPr

function openPanel<T = AnyType>(name: string, panelData?: T, config?: SidePanelConfig) {
if (openedPanels.includes(name)) {
setOpenedPanels([...openedPanels.filter(panel => panel !== name), name]);
setOpenedPanels(openedPanels.filter(panel => panel !== name));
setData([...data.filter(([panel]) => panel !== name), [name, panelData]]);
setTimeout(() => {
setOpenedPanels([...openedPanels, name]);
}, SIDE_PANEL_ANIMATION_DURATION * 1000);
} else {
setOpenedPanels([...openedPanels, name]);
setData([...data, [name, panelData]]);
Expand All @@ -117,8 +124,9 @@ export function SidePanelsProvider({ children, classNames }: SidePanelsContextPr

const {
gap,
width,
width = 0,
closedWidth = 0,
type = "drawer",
} = useMemo(() => {
if (openedPanels.length === 0) {
return defaultConfig;
Expand All @@ -132,8 +140,12 @@ export function SidePanelsProvider({ children, classNames }: SidePanelsContextPr
return closedWidth;
}

return width + (gap || 0);
}, [openedPanels, gap, width, closedWidth]);
if (type === "container") {
return width + (gap || 0);
}

return closedWidth;
}, [openedPanels, gap, width, closedWidth, type]);

return (
<SidePanelsContext.Provider
Expand All @@ -156,7 +168,13 @@ export function SidePanelsProvider({ children, classNames }: SidePanelsContextPr
{!isTablet && (
<AnimatedColumn width={panelSize} initialWidth={closedWidth} className={cn("h-full", classNames?.column)}>
<div
className={cn("relative h-full w-full overflow-hidden", classNames?.inner)}
className={cn(
"relative z-[99] h-full w-full",
{
"overflow-hidden": type === "container",
},
classNames?.inner
)}
ref={container}
style={{
paddingLeft: `${gap}rem` || 0,
Expand Down
4 changes: 3 additions & 1 deletion shared/features/side-panels/side-panels.types.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { PropsWithChildren, RefObject } from "react";

export type SidePanelType = "drawer" | "container";
export interface SidePanelConfig {
width: number;
width?: number;
closedWidth?: number;
gap?: number;
type?: SidePanelType;
}

export interface SidePanelsContextInterface {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ export function AccordionProjectContributors({
sorting,
setSorting,
}: AccordionProjectContributorsProps) {
const { open: openContributor } = useContributorSidePanel();
const { open: openContributor } = useContributorSidePanel({
type: "container",
});
const { data, isLoading, isError, hasNextPage, fetchNextPage, isFetchingNextPage } =
IssueReactQueryAdapter.client.useGetIssueApplicants({
pathParams: { contributionUuid: contributionId },
Expand Down