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

fix: sidebar navigation scrolling bug + housecleaning #1638

Merged
merged 2 commits into from
Oct 10, 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
2 changes: 1 addition & 1 deletion packages/ui/app/src/sidebar/DismissableSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export function DismissableSidebar({ className }: { className?: string }): React
set(DESKTOP_SIDEBAR_OPEN_ATOM, (prev) => {
if (event.clientX < 20) {
return true;
} else if (prev && event.target instanceof HTMLElement) {
} else if (prev && event.target instanceof Node) {
return sidebarRef.current?.contains(event.target) ?? false;
} else {
return false;
Expand Down
5 changes: 3 additions & 2 deletions packages/ui/app/src/sidebar/SidebarLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
useImperativeHandle,
useRef,
} from "react";
import { useCallbackOne } from "use-memo-one";
import { IS_READY_ATOM, SIDEBAR_SCROLL_CONTAINER_ATOM, useAtomEffect, useCloseMobileSidebar } from "../atoms";
import { FernLink } from "../components/FernLink";
import { useHref } from "../hooks/useHref";
Expand Down Expand Up @@ -205,10 +206,10 @@ export const SidebarSlugLink = forwardRef<HTMLDivElement, PropsWithChildren<Side
const closeMobileSidebar = useCloseMobileSidebar();

useAtomEffect(
useCallback(
useCallbackOne(
(get) => {
if (props.selected) {
scrollToCenter(get(SIDEBAR_SCROLL_CONTAINER_ATOM), ref.current, !get(IS_READY_ATOM));
scrollToCenter(get.peek(SIDEBAR_SCROLL_CONTAINER_ATOM), ref.current, get.peek(IS_READY_ATOM));
}
},
[props.selected],
Expand Down
18 changes: 0 additions & 18 deletions packages/ui/app/src/sidebar/nodes/SidebarApiGroupNode.tsx

This file was deleted.

32 changes: 21 additions & 11 deletions packages/ui/app/src/sidebar/nodes/SidebarApiPackageChild.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type * as FernNavigation from "@fern-api/fdr-sdk/navigation";
import { visitDiscriminatedUnion } from "@fern-api/ui-core-utils";
import { UnreachableCaseError } from "ts-essentials";
import { SidebarApiLeafNode } from "./SidebarApiLeafNode";
import { SidebarApiPackageNode } from "./SidebarApiPackageNode";
import { SidebarChangelogNode } from "./SidebarChangelogNode";
Expand All @@ -14,14 +14,24 @@ interface SidebarApiPackageChild {
}

export function SidebarApiPackageChild({ node, depth, shallow }: SidebarApiPackageChild): React.ReactElement {
return visitDiscriminatedUnion(node)._visit({
page: (node) => <SidebarPageNode node={node} depth={depth} shallow={shallow} />,
link: (node) => <SidebarLinkNode node={node} depth={depth} />,
endpoint: (node) => <SidebarApiLeafNode node={node} depth={depth} shallow={shallow} />,
endpointPair: (node) => <SidebarEndpointPairNode node={node} depth={depth} shallow={shallow} />,
webSocket: (node) => <SidebarApiLeafNode node={node} depth={depth} shallow={shallow} />,
webhook: (node) => <SidebarApiLeafNode node={node} depth={depth} shallow={shallow} />,
apiPackage: (node) => <SidebarApiPackageNode node={node} depth={depth} />,
changelog: (node) => <SidebarChangelogNode node={node} depth={depth} />,
});
switch (node.type) {
case "page":
return <SidebarPageNode node={node} depth={depth} shallow={shallow} />;
case "link":
return <SidebarLinkNode node={node} depth={depth} />;
case "endpoint":
return <SidebarApiLeafNode node={node} depth={depth} shallow={shallow} />;
case "endpointPair":
return <SidebarEndpointPairNode node={node} depth={depth} shallow={shallow} />;
case "webSocket":
return <SidebarApiLeafNode node={node} depth={depth} shallow={shallow} />;
case "webhook":
return <SidebarApiLeafNode node={node} depth={depth} shallow={shallow} />;
case "apiPackage":
return <SidebarApiPackageNode node={node} depth={depth} />;
case "changelog":
return <SidebarChangelogNode node={node} depth={depth} />;
default:
throw new UnreachableCaseError(node);
}
}
41 changes: 7 additions & 34 deletions packages/ui/app/src/sidebar/nodes/SidebarApiPackageNode.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type * as FernNavigation from "@fern-api/fdr-sdk/navigation";
import * as FernNavigation from "@fern-api/fdr-sdk/navigation";
import { useCallback } from "react";
import {
useIsApiReferenceShallowLink,
Expand All @@ -10,6 +10,8 @@ import {
import { CollapsibleSidebarGroup } from "../CollapsibleSidebarGroup";
import { SidebarSlugLink } from "../SidebarLink";
import { SidebarApiPackageChild } from "./SidebarApiPackageChild";
import { SidebarGroupApiReferenceNode } from "./SidebarGroupApiReferenceNode";
import { SidebarPageNode } from "./SidebarPageNode";

export interface SidebarApiPackageNodeProps {
node: FernNavigation.ApiReferenceNode | FernNavigation.ApiPackageNode;
Expand All @@ -35,45 +37,16 @@ export function SidebarApiPackageNode({
[depth, shallow],
);

if (node.children.length === 0) {
if (node.overviewPageId == null) {
return null;
}

if (node.hidden && !selected) {
return null;
}

return (
<SidebarSlugLink
nodeId={node.id}
className={className}
slug={node.slug}
depth={Math.max(depth - 1, 0)}
title={node.title}
authed={node.authed}
selected={selected}
icon={node.icon}
hidden={node.hidden}
shallow={shallow}
/>
);
if (node.children.length === 0 && FernNavigation.hasMarkdown(node)) {
return <SidebarPageNode node={node} depth={depth} className={className} shallow={shallow} />;
}

if (node.hidden && !childSelected) {
if (node.children.length === 0 || (node.hidden && !childSelected)) {
return null;
}

if (node.type === "apiReference" && node.hideTitle) {
return (
<ul className="fern-sidebar-group">
{node.children.map((child) => (
<li key={child.id}>
<SidebarApiPackageChild node={child} depth={depth} shallow={shallow} />
</li>
))}
</ul>
);
return <SidebarGroupApiReferenceNode node={node} depth={depth} />;
}

const showIndicator = childSelected && !expanded;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { FernNavigation } from "@fern-api/fdr-sdk";
import { useIsApiReferenceShallowLink } from "../../atoms";
import { SidebarApiPackageChild } from "./SidebarApiPackageChild";

interface SidebarGroupApiReferenceNodeProps {
node: FernNavigation.ApiReferenceNode;
depth: number;
}

export function SidebarGroupApiReferenceNode({ node, depth }: SidebarGroupApiReferenceNodeProps): React.ReactElement {
const shallow = useIsApiReferenceShallowLink(node);

return (
<ul className="fern-sidebar-group">
{node.children.map((child) => (
<li key={child.id}>
<SidebarApiPackageChild node={child} depth={depth} shallow={shallow} />
</li>
))}
</ul>
);
}
12 changes: 1 addition & 11 deletions packages/ui/app/src/sidebar/nodes/SidebarLinkNode.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type * as FernNavigation from "@fern-api/fdr-sdk/navigation";
import { OpenNewWindow } from "iconoir-react";
import { useEffect, useState } from "react";
import { SidebarLink } from "../SidebarLink";

interface SidebarLinkNodeProps {
Expand All @@ -10,23 +9,14 @@ interface SidebarLinkNodeProps {
}

export function SidebarLinkNode({ node, depth, className }: SidebarLinkNodeProps): React.ReactElement {
// TODO: handle this more gracefully, and make this SSG-friendly
const [origin, setOrigin] = useState<string>("xxx");
useEffect(() => {
setOrigin(window.location.origin);
}, []);

return (
<SidebarLink
icon={node.icon}
nodeId={node.id}
className={className}
depth={Math.max(depth - 1, 0)}
title={node.title}
rightElement={
node.url.startsWith("http") &&
!node.url.startsWith(origin) && <OpenNewWindow className="size-4 self-center text-faded" />
}
rightElement={<OpenNewWindow className="size-4 self-center text-faded" />}
href={node.url}
/>
);
Expand Down
35 changes: 21 additions & 14 deletions packages/ui/app/src/sidebar/nodes/SidebarNavigationChild.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type * as FernNavigation from "@fern-api/fdr-sdk/navigation";
import { visitDiscriminatedUnion } from "@fern-api/ui-core-utils";
import clsx from "clsx";
import dynamic from "next/dynamic";
import { UnreachableCaseError } from "ts-essentials";
import { SidebarApiPackageNode } from "./SidebarApiPackageNode";
import { SidebarLinkNode } from "./SidebarLinkNode";
import { SidebarPageNode } from "./SidebarPageNode";
Expand All @@ -19,17 +19,24 @@ interface SidebarNavigationChildProps {
}

export function SidebarNavigationChild({ node, depth, root }: SidebarNavigationChildProps): React.ReactElement {
return visitDiscriminatedUnion(node)._visit({
apiReference: (apiRef) => <SidebarApiPackageNode node={apiRef} depth={depth} />,
section: (section) => (
<SidebarSectionNode
node={section}
depth={depth}
className={clsx({ "font-semibold !text-text-default": root })}
/>
),
page: (page) => <SidebarPageNode node={page} depth={depth} />,
link: (link) => <SidebarLinkNode node={link} depth={depth} />,
changelog: (changelog) => <SidebarChangelogNode node={changelog} depth={depth} />,
});
switch (node.type) {
case "apiReference":
return <SidebarApiPackageNode node={node} depth={depth} />;
case "section":
return (
<SidebarSectionNode
node={node}
depth={depth}
className={clsx({ "font-semibold !text-text-default": root })}
/>
);
case "page":
return <SidebarPageNode node={node} depth={depth} />;
case "link":
return <SidebarLinkNode node={node} depth={depth} />;
case "changelog":
return <SidebarChangelogNode node={node} depth={depth} />;
default:
throw new UnreachableCaseError(node);
}
}
12 changes: 10 additions & 2 deletions packages/ui/app/src/sidebar/nodes/SidebarPageNode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,20 @@ import { useIsSelectedSidebarNode } from "../../atoms";
import { SidebarSlugLink } from "../SidebarLink";

interface SidebarPageNodeProps {
node: FernNavigation.PageNode;
node: FernNavigation.NavigationNodeWithMarkdown;
depth: number;
className?: string;
linkClassName?: string;
shallow?: boolean;
}

export function SidebarPageNode({ node, depth, className, shallow }: SidebarPageNodeProps): React.ReactElement | null {
export function SidebarPageNode({
node,
depth,
className,
linkClassName,
shallow,
}: SidebarPageNodeProps): React.ReactElement | null {
const selected = useIsSelectedSidebarNode(node.id);

if (node.hidden && !selected) {
Expand All @@ -20,6 +27,7 @@ export function SidebarPageNode({ node, depth, className, shallow }: SidebarPage
<SidebarSlugLink
nodeId={node.id}
className={className}
linkClassName={linkClassName}
slug={node.slug}
depth={Math.max(depth - 1, 0)}
title={node.title}
Expand Down
32 changes: 9 additions & 23 deletions packages/ui/app/src/sidebar/nodes/SidebarRootApiPackageNode.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type * as FernNavigation from "@fern-api/fdr-sdk/navigation";
import * as FernNavigation from "@fern-api/fdr-sdk/navigation";
import clsx from "clsx";
import { useIsApiReferenceShallowLink, useIsChildSelected, useIsSelectedSidebarNode } from "../../atoms";
import { SidebarSlugLink } from "../SidebarLink";
import { useIsApiReferenceShallowLink, useIsChildSelected } from "../../atoms";
import { SidebarApiPackageChild } from "./SidebarApiPackageChild";
import { SidebarPageNode } from "./SidebarPageNode";
import { SidebarRootHeading } from "./SidebarRootHeading";

export interface SidebarRootApiPackageNodeProps {
Expand All @@ -14,36 +14,22 @@ export function SidebarRootApiPackageNode({
node,
className,
}: SidebarRootApiPackageNodeProps): React.ReactElement | null {
const selected = useIsSelectedSidebarNode(node.id);
const childSelected = useIsChildSelected(node.id);
const shallow = useIsApiReferenceShallowLink(node);

if (node.children.length === 0) {
if (node.overviewPageId == null) {
return null;
}

if (node.hidden && !selected) {
return null;
}

if (node.children.length === 0 && FernNavigation.hasMarkdown(node)) {
return (
<SidebarSlugLink
nodeId={node.id}
linkClassName="font-semibold !text-text-default"
<SidebarPageNode
node={node}
depth={0}
className={className}
slug={node.slug}
title={node.title}
selected={selected}
icon={node.icon}
hidden={node.hidden}
authed={node.authed}
linkClassName="font-semibold !text-text-default"
shallow={shallow}
/>
);
}

if (node.hidden && !childSelected) {
if (node.children.length === 0 || (node.hidden && !childSelected)) {
return null;
}

Expand Down
Loading
Loading