Skip to content

Commit

Permalink
chore: add header to sidebar + add full width state (#37597)
Browse files Browse the repository at this point in the history
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

## Release Notes

- **New Features**
- Enhanced `_Sheet` and `_Sidebar` components with new props for
handling transition events (`onEnter`, `onExit`).
- Introduced `SidebarContent` component for better organization of
sidebar content.
  - Added a new story for `Sidebar` demonstrating render prop usage.

- **Improvements**
- Updated state management in `SidebarProvider` for more flexible
sidebar behavior.
  - Improved CSS transitions for smoother animations in the sidebar.
- Enhanced type definitions for better clarity and functionality in
state management.

- **Bug Fixes**
- Adjusted rendering logic to ensure correct display of sidebar states.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->


## Automation

/ok-to-test tags="@tag.Sanity"

### 🔍 Cypress test results
<!-- This is an auto-generated comment: Cypress test results  -->
> [!TIP]
> 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉
> Workflow run:
<https://github.com/appsmithorg/appsmith/actions/runs/11935118755>
> Commit: a8170df
> <a
href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=11935118755&attempt=1"
target="_blank">Cypress dashboard</a>.
> Tags: `@tag.Sanity`
> Spec:
> <hr>Wed, 20 Nov 2024 14:52:18 UTC
<!-- end of auto-generated comment: Cypress test results  -->


## Communication
Should the DevRel and Marketing teams inform users about this change?
- [ ] Yes
- [x] No


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **Chores**
- Removed several configuration files related to observability tools,
including Docker Compose, Grafana dashboards, data sources, and
Prometheus settings.
- These changes streamline the observability setup by eliminating
outdated or unused configurations.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
  • Loading branch information
jsartisan authored Nov 21, 2024
1 parent 81b7727 commit 89f9b59
Show file tree
Hide file tree
Showing 8 changed files with 240 additions and 61 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ export function _Sheet(props: SheetProps, ref: Ref<HTMLDivElement>) {
children,
className,
isOpen,
onEnter,
onEntered,
onExit,
onExited,
onOpenChange,
position = "start",
Expand All @@ -31,7 +33,9 @@ export function _Sheet(props: SheetProps, ref: Ref<HTMLDivElement>) {
<CSSTransition
in={isOpen}
nodeRef={overlayRef}
onEnter={onEnter}
onEntered={onEntered}
onExit={onExit}
onExited={onExited}
timeout={300}
unmountOnExit
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ export interface SheetProps
* @default 'start'
*/
position?: "start" | "end";
onEnter?: () => void;
onEntered?: () => void;
onExit?: () => void;
onExited?: () => void;
}
Original file line number Diff line number Diff line change
@@ -1,30 +1,65 @@
import clsx from "clsx";
import * as React from "react";
import { type Ref, useRef } from "react";
import { type Ref, useRef, useState } from "react";
import { CSSTransition } from "react-transition-group";

import { Sheet } from "../../Sheet";
import { useSidebar } from "./use-sidebar";
import styles from "./styles.module.css";
import { useSidebar } from "./use-sidebar";
import type { SidebarProps } from "./types";
import { CSSTransition } from "react-transition-group";

import { SidebarContent } from "./SidebarContent";

const _Sidebar = (props: SidebarProps, ref: Ref<HTMLDivElement>) => {
const {
children,
className,
collapsible = "offcanvas",
onEntered,
onExited,
onEnter: onEnterProp,
onEntered: onEnteredProp,
onExit: onExitProp,
onExited: onExitedProp,
side = "start",
title,
variant = "sidebar",
...rest
} = props;
const { isMobile, setOpen, state } = useSidebar();
const [isAnimating, setIsAnimating] = useState(false);
const { isMobile, setState, state } = useSidebar();
const sidebarRef = useRef<HTMLDivElement>();

const onEnter = () => {
setIsAnimating(true);
onEnterProp?.();
};

const onEntered = () => {
setIsAnimating(false);
onEnteredProp?.();
};

const onExit = () => {
setIsAnimating(true);
onExitProp?.();
};

const onExited = () => {
setIsAnimating(false);
onExitedProp?.();
};

const content = (
<SidebarContent title={title}>
{typeof children === "function"
? children({ isAnimating, state })
: children}
</SidebarContent>
);

if (collapsible === "none") {
return (
<div className={clsx(className)} ref={ref} {...props}>
{children}
{content}
</div>
);
}
Expand All @@ -33,38 +68,52 @@ const _Sidebar = (props: SidebarProps, ref: Ref<HTMLDivElement>) => {
return (
<Sheet
isOpen={state === "expanded"}
onEnter={onEnter}
onEntered={onEntered}
onExit={onExit}
onExited={onExited}
onOpenChange={setOpen}
onOpenChange={(isOpen) => setState(isOpen ? "expanded" : "collapsed")}
position={side}
>
{children}
{content}
</Sheet>
);
}

return (
<CSSTransition
in={state === "expanded"}
in={state === "full-width"}
nodeRef={sidebarRef}
onEnter={onEnter}
onEntered={onEntered}
onExit={onExit}
onExited={onExited}
timeout={300}
>
<div
className={clsx(styles.mainSidebar)}
data-collapsible={state === "collapsed" ? collapsible : ""}
data-side={side}
data-state={state}
data-variant={variant}
// @ts-expect-error TS is unable to infer the correct type for the render prop
ref={sidebarRef}
<CSSTransition
in={state === "expanded"}
nodeRef={sidebarRef}
onEnter={onEnter}
onEntered={onEntered}
onExit={onExit}
onExited={onExited}
timeout={300}
>
<div className={styles.fakeSidebar} />
<div className={clsx(styles.sidebar, className)} ref={ref} {...rest}>
<div className={styles.sidebarContainer}>{children}</div>
<div
className={clsx(styles.mainSidebar)}
data-collapsible={state === "collapsed" ? collapsible : ""}
data-side={side}
data-state={state}
data-variant={variant}
// @ts-expect-error TS is unable to infer the correct type for the render prop
ref={sidebarRef}
>
<div className={styles.fakeSidebar} />
<div className={clsx(styles.sidebar, className)} ref={ref} {...rest}>
<div className={styles.sidebarContainer}>{content}</div>
</div>
</div>
</div>
</CSSTransition>
</CSSTransition>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,59 @@
import clsx from "clsx";
import React, { type ComponentProps, type Ref } from "react";
import React, { type Ref } from "react";

import { Flex } from "../../Flex";
import { Text } from "../../Text";
import { Button } from "../../Button";
import styles from "./styles.module.css";
import { useSidebar } from "./use-sidebar";

interface SidebarContentProps {
title?: string;
className?: string;
children: React.ReactNode;
}

const _SidebarContent = (
props: ComponentProps<"div">,
props: SidebarContentProps,
ref: Ref<HTMLDivElement>,
) => {
const { className, ...rest } = props;
const { children, className, title, ...rest } = props;
const { isMobile, setState, state } = useSidebar();

return (
<div
className={clsx(styles.sidebarContent, className)}
data-sidebar="content"
ref={ref}
{...rest}
/>
>
<Flex direction="column" height="100%" isInner>
<Flex
alignItems="center"
className={styles.sidebarHeader}
isInner
justifyContent="space-between"
padding="spacing-2"
>
{Boolean(title) && <Text lineClamp={1}>{title}</Text>}
{!isMobile && (
<Button
color="neutral"
icon={
state === "full-width"
? "arrows-diagonal-minimize"
: "arrows-diagonal-2"
}
onPress={() =>
setState(state === "full-width" ? "expanded" : "full-width")
}
variant="ghost"
/>
)}
</Flex>
<div className={styles.sidebarContentInner}>{children}</div>
</Flex>
</div>
);
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import clsx from "clsx";
import React, { type Ref, useCallback, useState } from "react";

import type {
SidebarContextType,
SidebarProviderProps,
SidebarState,
} from "./types";
import styles from "./styles.module.css";
import { SidebarContext } from "./context";
import { useIsMobile } from "./use-mobile";
import { SIDEBAR_CONSTANTS } from "./constants";
import type { SidebarContextType, SidebarProviderProps } from "./types";

export const _SidebarProvider = (
props: SidebarProviderProps,
Expand All @@ -14,32 +18,32 @@ export const _SidebarProvider = (
const {
children,
className,
defaultOpen = true,
isOpen: openProp,
onOpen: setOpenProp,
defaultState = "expanded",
onStateChange: setStateProp,
state: stateProp,
style,
...rest
} = props;
const isMobile = useIsMobile();

const [_open, _setOpen] = useState(defaultOpen);
const open = openProp ?? _open;
const setOpen = useCallback(
(value: boolean | ((value: boolean) => boolean)) => {
const openState = typeof value === "function" ? value(open) : value;
const [_state, _setState] = useState<SidebarState>(defaultState);
const state = stateProp ?? _state;
const setState = useCallback(
(value: SidebarState | ((value: SidebarState) => SidebarState)) => {
const computedState = typeof value === "function" ? value(state) : value;

if (setOpenProp) {
setOpenProp(openState);
if (setStateProp) {
setStateProp(computedState);
} else {
_setOpen(openState);
_setState(computedState);
}
},
[setOpenProp, open],
[setStateProp, state],
);

const toggleSidebar = React.useCallback(() => {
return isMobile ? setOpen((open) => !open) : setOpen((open) => !open);
}, [isMobile, setOpen]);
return state === "collapsed" ? setState("expanded") : setState("collapsed");
}, [setState, state]);

React.useEffect(
function handleKeyboardShortcuts() {
Expand All @@ -60,17 +64,14 @@ export const _SidebarProvider = (
[toggleSidebar, isMobile],
);

const state = open ? "expanded" : "collapsed";

const contextValue = React.useMemo<SidebarContextType>(
() => ({
state,
open,
setOpen,
setState,
isMobile,
toggleSidebar,
}),
[state, open, setOpen, isMobile, toggleSidebar],
[state, setState, isMobile, toggleSidebar],
);

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
height: 100%;
width: var(--sidebar-width);
background-color: transparent;
transition: width 300ms linear;
transition: width 300ms ease-in-out;
}

.mainSidebar[data-side="right"] .fakeSidebar {
Expand Down Expand Up @@ -76,9 +76,14 @@
height: 100%;
width: var(--sidebar-width);
transition:
left 300ms linear,
right 300ms linear,
width 300ms linear;
left 300ms ease-in-out,
right 300ms ease-in-out,
width 300ms ease-in-out;
background-color: var(--color-bg-elevation-2);
}

[data-state="full-width"] .sidebar {
width: 100%;
}

@container (min-width: 768px) {
Expand Down Expand Up @@ -131,6 +136,20 @@
border-inline-start: var(--border-width-1) solid var(--color-bd-elevation-1);
}

.mainSidebar[data-state="full-width"][data-side="start"]:is(
[data-variant="sidebar"]
)
.sidebar {
border-inline-end: none;
}

.mainSidebar[data-state="full-width"][data-side="end"]:is(
[data-variant="sidebar"]
)
.sidebar {
border-inline-start: none;
}

/**
*-----------------------------------------------------
* SIDEBAR CONTAINER
Expand Down Expand Up @@ -166,6 +185,13 @@
height: 100%;
}

.sidebarContentInner {
flex-grow: 1;
overflow-y: auto;
overflow-x: hidden;
width: 100%;
}

/**
*-----------------------------------------------------
* SIDEBAR INSET
Expand Down Expand Up @@ -201,3 +227,12 @@
margin-left: 0;
}
}

/**
*-----------------------------------------------------
* SIDEBAR HEADER
*-----------------------------------------------------
*/
.sidebarHeader {
border-bottom: var(--border-width-1) solid var(--color-bd-elevation-1);
}
Loading

0 comments on commit 89f9b59

Please sign in to comment.