From 22a142369090c27180803cb7946684315d039809 Mon Sep 17 00:00:00 2001 From: David Corbitt Date: Fri, 18 Aug 2023 01:33:13 -0700 Subject: [PATCH] Square header border when scrolled down --- .../OutputsTable/AddVariantButton.tsx | 2 +- .../OutputsTable/ScenarioEditor.tsx | 2 +- .../OutputsTable/ScenariosHeader.tsx | 2 +- .../VariantHeader/VariantHeader.tsx | 6 ++-- .../VariantHeader/VariantHeaderMenuButton.tsx | 13 +++---- .../components/OutputsTable/VariantStats.tsx | 2 +- .../{ => OutputsTable}/constants.ts | 0 app/src/components/OutputsTable/index.tsx | 10 +++--- .../OutputsTable/useHasScrolledPast.tsx | 34 +++++++++++++++++++ app/src/components/nav/ProjectMenu.tsx | 8 ++++- .../pages/experiments/[experimentSlug].tsx | 2 +- 11 files changed, 62 insertions(+), 19 deletions(-) rename app/src/components/{ => OutputsTable}/VariantHeader/VariantHeader.tsx (97%) rename app/src/components/{ => OutputsTable}/VariantHeader/VariantHeaderMenuButton.tsx (93%) rename app/src/components/{ => OutputsTable}/constants.ts (100%) create mode 100644 app/src/components/OutputsTable/useHasScrolledPast.tsx diff --git a/app/src/components/OutputsTable/AddVariantButton.tsx b/app/src/components/OutputsTable/AddVariantButton.tsx index cef9fbd..b4cc540 100644 --- a/app/src/components/OutputsTable/AddVariantButton.tsx +++ b/app/src/components/OutputsTable/AddVariantButton.tsx @@ -8,7 +8,7 @@ import { useHandledAsyncCallback, useVisibleScenarioIds, } from "~/utils/hooks"; -import { cellPadding } from "../constants"; +import { cellPadding } from "./constants"; import { ActionButton } from "./ScenariosHeader"; export default function AddVariantButton() { diff --git a/app/src/components/OutputsTable/ScenarioEditor.tsx b/app/src/components/OutputsTable/ScenarioEditor.tsx index 8e2872f..b44a430 100644 --- a/app/src/components/OutputsTable/ScenarioEditor.tsx +++ b/app/src/components/OutputsTable/ScenarioEditor.tsx @@ -16,7 +16,7 @@ import { VStack, } from "@chakra-ui/react"; import { BsArrowsAngleExpand, BsX } from "react-icons/bs"; -import { cellPadding } from "../constants"; +import { cellPadding } from "./constants"; import { FloatingLabelInput } from "./FloatingLabelInput"; import { ScenarioEditorModal } from "./ScenarioEditorModal"; diff --git a/app/src/components/OutputsTable/ScenariosHeader.tsx b/app/src/components/OutputsTable/ScenariosHeader.tsx index aaca359..7e18286 100644 --- a/app/src/components/OutputsTable/ScenariosHeader.tsx +++ b/app/src/components/OutputsTable/ScenariosHeader.tsx @@ -11,7 +11,7 @@ import { IconButton, Spinner, } from "@chakra-ui/react"; -import { cellPadding } from "../constants"; +import { cellPadding } from "./constants"; import { useExperiment, useExperimentAccess, diff --git a/app/src/components/VariantHeader/VariantHeader.tsx b/app/src/components/OutputsTable/VariantHeader/VariantHeader.tsx similarity index 97% rename from app/src/components/VariantHeader/VariantHeader.tsx rename to app/src/components/OutputsTable/VariantHeader/VariantHeader.tsx index e86fd59..1cdd6ba 100644 --- a/app/src/components/VariantHeader/VariantHeader.tsx +++ b/app/src/components/OutputsTable/VariantHeader/VariantHeader.tsx @@ -1,11 +1,11 @@ import { useState, type DragEvent } from "react"; -import { type PromptVariant } from "../OutputsTable/types"; +import { type PromptVariant } from "../types"; import { api } from "~/utils/api"; import { RiDraggable } from "react-icons/ri"; import { useExperimentAccess, useHandledAsyncCallback } from "~/utils/hooks"; import { HStack, Icon, Text, GridItem, type GridItemProps } from "@chakra-ui/react"; // Changed here import { cellPadding, headerMinHeight } from "../constants"; -import AutoResizeTextArea from "../AutoResizeTextArea"; +import AutoResizeTextArea from "../../AutoResizeTextArea"; import VariantHeaderMenuButton from "./VariantHeaderMenuButton"; export default function VariantHeader( @@ -75,7 +75,7 @@ export default function VariantHeader( padding={0} sx={{ position: "sticky", - top: "-2", + top: "0", // Ensure that the menu always appears above the sticky header of other variants zIndex: menuOpen ? "dropdown" : 10, }} diff --git a/app/src/components/VariantHeader/VariantHeaderMenuButton.tsx b/app/src/components/OutputsTable/VariantHeader/VariantHeaderMenuButton.tsx similarity index 93% rename from app/src/components/VariantHeader/VariantHeaderMenuButton.tsx rename to app/src/components/OutputsTable/VariantHeader/VariantHeaderMenuButton.tsx index add2757..6b43c67 100644 --- a/app/src/components/VariantHeader/VariantHeaderMenuButton.tsx +++ b/app/src/components/OutputsTable/VariantHeader/VariantHeaderMenuButton.tsx @@ -1,6 +1,4 @@ -import { type PromptVariant } from "../OutputsTable/types"; -import { api } from "~/utils/api"; -import { useHandledAsyncCallback, useVisibleScenarioIds } from "~/utils/hooks"; +import { useState } from "react"; import { Icon, Menu, @@ -14,10 +12,13 @@ import { } from "@chakra-ui/react"; import { BsFillTrashFill, BsGear, BsStars } from "react-icons/bs"; import { FaRegClone } from "react-icons/fa"; -import { useState } from "react"; -import { RefinePromptModal } from "../RefinePromptModal/RefinePromptModal"; import { RiExchangeFundsFill } from "react-icons/ri"; -import { ChangeModelModal } from "../ChangeModelModal/ChangeModelModal"; + +import { api } from "~/utils/api"; +import { useHandledAsyncCallback, useVisibleScenarioIds } from "~/utils/hooks"; +import { type PromptVariant } from "../types"; +import { RefinePromptModal } from "../../RefinePromptModal/RefinePromptModal"; +import { ChangeModelModal } from "../../ChangeModelModal/ChangeModelModal"; export default function VariantHeaderMenuButton({ variant, diff --git a/app/src/components/OutputsTable/VariantStats.tsx b/app/src/components/OutputsTable/VariantStats.tsx index fd7a219..f0c3e74 100644 --- a/app/src/components/OutputsTable/VariantStats.tsx +++ b/app/src/components/OutputsTable/VariantStats.tsx @@ -1,6 +1,6 @@ import { HStack, Icon, Text, useToken } from "@chakra-ui/react"; import { type PromptVariant } from "./types"; -import { cellPadding } from "../constants"; +import { cellPadding } from "./constants"; import { api } from "~/utils/api"; import chroma from "chroma-js"; import { BsCurrencyDollar } from "react-icons/bs"; diff --git a/app/src/components/constants.ts b/app/src/components/OutputsTable/constants.ts similarity index 100% rename from app/src/components/constants.ts rename to app/src/components/OutputsTable/constants.ts diff --git a/app/src/components/OutputsTable/index.tsx b/app/src/components/OutputsTable/index.tsx index 1dd10e4..888fca6 100644 --- a/app/src/components/OutputsTable/index.tsx +++ b/app/src/components/OutputsTable/index.tsx @@ -1,15 +1,16 @@ -import { Grid, GridItem, type GridItemProps } from "@chakra-ui/react"; +import { Box, Grid, GridItem, type GridItemProps } from "@chakra-ui/react"; import { api } from "~/utils/api"; import AddVariantButton from "./AddVariantButton"; import ScenarioRow from "./ScenarioRow"; import VariantEditor from "./VariantEditor"; -import VariantHeader from "../VariantHeader/VariantHeader"; +import VariantHeader from "./VariantHeader/VariantHeader"; import VariantStats from "./VariantStats"; import { ScenariosHeader } from "./ScenariosHeader"; import { borders } from "./styles"; import { useScenarios } from "~/utils/hooks"; import ScenarioPaginator from "./ScenarioPaginator"; import { Fragment } from "react"; +import useScrolledPast from "./useHasScrolledPast"; export default function OutputsTable({ experimentId }: { experimentId: string | undefined }) { const variants = api.promptVariants.list.useQuery( @@ -18,6 +19,7 @@ export default function OutputsTable({ experimentId }: { experimentId: string | ); const scenarios = useScenarios(); + const shouldFlattenHeader = useScrolledPast(50); if (!variants.data || !scenarios.data) return null; @@ -63,8 +65,8 @@ export default function OutputsTable({ experimentId }: { experimentId: string | variant={variant} canHide={variants.data.length > 1} rowStart={1} - borderTopLeftRadius={isFirst ? 8 : 0} - borderTopRightRadius={isLast ? 8 : 0} + borderTopLeftRadius={isFirst && !shouldFlattenHeader ? 8 : 0} + borderTopRightRadius={isLast && !shouldFlattenHeader ? 8 : 0} {...sharedProps} /> diff --git a/app/src/components/OutputsTable/useHasScrolledPast.tsx b/app/src/components/OutputsTable/useHasScrolledPast.tsx new file mode 100644 index 0000000..a870046 --- /dev/null +++ b/app/src/components/OutputsTable/useHasScrolledPast.tsx @@ -0,0 +1,34 @@ +import { useState, useEffect } from "react"; + +const useScrolledPast = (scrollThreshold: number) => { + const [hasScrolledPast, setHasScrolledPast] = useState(true); + + useEffect(() => { + const container = document.getElementById("output-container"); + + if (!container) { + console.warn('Element with id "outputs-container" not found.'); + return; + } + + const checkScroll = () => { + const { scrollTop } = container; + + // Check if scrollTop is greater than or equal to scrollThreshold + setHasScrolledPast(scrollTop > scrollThreshold); + }; + + checkScroll(); + + container.addEventListener("scroll", checkScroll); + + // Cleanup + return () => { + container.removeEventListener("scroll", checkScroll); + }; + }, []); + + return hasScrolledPast; +}; + +export default useScrolledPast; diff --git a/app/src/components/nav/ProjectMenu.tsx b/app/src/components/nav/ProjectMenu.tsx index dcc5f9a..f4441d6 100644 --- a/app/src/components/nav/ProjectMenu.tsx +++ b/app/src/components/nav/ProjectMenu.tsx @@ -67,7 +67,13 @@ export default function ProjectMenu() { ); return ( - + - +