Skip to content

Commit

Permalink
touchup: add prev/next selected part
Browse files Browse the repository at this point in the history
can keep an eye on how it feels. seems a little awkward because
it takes up a whole row in the pane, but trying to fit it on the same
row as the content's title seemed challenging to design without it
looking even more awkward.
  • Loading branch information
keyserj committed Feb 13, 2025
1 parent 5b90a0c commit f19526f
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 6 deletions.
2 changes: 1 addition & 1 deletion src/web/topic/components/TopicPane/GraphPartDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export const GraphPartDetails = ({ graphPart, selectedTab, setSelectedTab }: Pro

return (
// flex & max-h to ensure content takes up no more than full height, allowing inner containers to control scrolling
<List className="flex max-h-full flex-col pb-0">
<List className="flex max-h-full flex-col py-0">
<div className="flex flex-col items-center">
{partIsNode ? (
// z-index to ensure hanging node indicators don't fall behind the next section's empty background
Expand Down
2 changes: 1 addition & 1 deletion src/web/topic/components/TopicPane/TopicDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ export const TopicDetails = ({ selectedTab, setSelectedTab }: Props) => {

return (
// flex & max-h to ensure content takes up no more than full height, allowing inner containers to control scrolling
<List className="flex max-h-full flex-col pb-0">
<List className="flex max-h-full flex-col py-0">
{/* max-w and wrap/break to handle long topic titles */}
<div className="flex items-center justify-center text-wrap break-all px-4">
{isPlaygroundTopic ? (
Expand Down
49 changes: 46 additions & 3 deletions src/web/topic/components/TopicPane/TopicPane.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { AutoStories, ChevronLeft, ChevronRight } from "@mui/icons-material";
import {
ArrowBack,
ArrowForward,
AutoStories,
ChevronLeft,
ChevronRight,
} from "@mui/icons-material";
import { TabContext, TabList, TabPanel } from "@mui/lab";
import { IconButton, Modal, Tab } from "@mui/material";
import { memo, useEffect, useState } from "react";
Expand All @@ -15,7 +21,39 @@ import {
} from "@/web/topic/components/TopicPane/TopicDetails";
import { StyledDrawer, drawerMinWidthRem } from "@/web/topic/components/TopicPane/TopicPane.styles";
import { TopicViews } from "@/web/topic/components/TopicPane/TopicViews";
import { useSelectedGraphPart } from "@/web/view/selectedPartStore";
import {
goBack,
goForward,
useCanGoBackForward,
useSelectedGraphPart,
} from "@/web/view/selectedPartStore";

const DetailsToolbar = () => {
const [canGoBack, canGoForward] = useCanGoBackForward();

return (
<div className="flex items-center justify-center">
<IconButton
color="inherit"
title="Previous Selection"
aria-label="Previous Selection"
onClick={goBack}
disabled={!canGoBack}
>
<ArrowBack />
</IconButton>
<IconButton
color="inherit"
title="Next Selection"
aria-label="Next Selection"
onClick={goForward}
disabled={!canGoForward}
>
<ArrowForward />
</IconButton>
</div>
);
};

type TopicTab = "Details" | "Views";
interface Props {
Expand Down Expand Up @@ -89,9 +127,14 @@ const TopicPaneBase = ({ anchor, tabs }: Props) => {
))}
</TabList>

{/* flex flex-col to put details toolbar above the content */}
{/* overflow-auto to allow tab content to scroll */}
{/* p-0 to allow tab content to manage its own padding, since e.g. dividers prefer not to be padded */}
<TabPanel key="Details" value="Details" className="overflow-auto p-0">
<TabPanel key="Details" value="Details" className="flex flex-col overflow-auto p-0">
{/* Toolbar centered above content to be near content's title, in hopes of implying that the */}
{/* back/forward buttons are to navigate to previous/next content. */}
<DetailsToolbar />

{selectedGraphPart !== null ? (
<GraphPartDetails
graphPart={selectedGraphPart}
Expand Down
21 changes: 20 additions & 1 deletion src/web/view/selectedPartStore.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { temporal } from "zundo";
import { create } from "zustand";
import { create, useStore } from "zustand";
import { persist } from "zustand/middleware";

import { emitter } from "@/web/common/event";
Expand Down Expand Up @@ -31,6 +31,9 @@ const useSelectedPartStore = create<SelectedPartStoreState>()(
),
);

// temporal store is a vanilla store, we need to wrap it to use it as a hook and be able to react to changes
const useTemporalStore = () => useStore(useSelectedPartStore.temporal);

// hooks
export const useSelectedGraphPart = () => {
const selectedGraphPartId = useSelectedPartStore((state) => state.selectedGraphPartId);
Expand All @@ -52,6 +55,14 @@ export const useIsAnyGraphPartSelected = (graphPartIds: string[]) => {
});
};

export const useCanGoBackForward = () => {
const temporalStore = useTemporalStore();

const canGoBack = temporalStore.pastStates.length > 0;
const canGoForward = temporalStore.futureStates.length > 0;
return [canGoBack, canGoForward];
};

// actions
export const setSelected = (graphPartId: string | null) => {
const { selectedGraphPartId } = useSelectedPartStore.getState();
Expand All @@ -62,6 +73,14 @@ export const setSelected = (graphPartId: string | null) => {
emitter.emit("partSelected", graphPartId);
};

export const goBack = () => {
useSelectedPartStore.temporal.getState().undo();
};

export const goForward = () => {
useSelectedPartStore.temporal.getState().redo();
};

// util actions
export const getSelectedGraphPart = () => {
const selectedGraphPartId = useSelectedPartStore.getState().selectedGraphPartId;
Expand Down

0 comments on commit f19526f

Please sign in to comment.