Use PageHeaderContainer for all breadcrumbs

This commit is contained in:
David Corbitt
2023-08-07 11:16:54 -07:00
parent 6b304f8456
commit 1a838824ae
10 changed files with 167 additions and 119 deletions

View File

@@ -25,6 +25,7 @@ declare module "nextjs-routes" {
| StaticRoute<"/home"> | StaticRoute<"/home">
| StaticRoute<"/"> | StaticRoute<"/">
| StaticRoute<"/sentry-example-page"> | StaticRoute<"/sentry-example-page">
| StaticRoute<"/settings">
| StaticRoute<"/world-champs"> | StaticRoute<"/world-champs">
| StaticRoute<"/world-champs/signup">; | StaticRoute<"/world-champs/signup">;

View File

@@ -12,7 +12,7 @@ import {
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import Head from "next/head"; import Head from "next/head";
import Link from "next/link"; import Link from "next/link";
import { BsGithub, BsPersonCircle } from "react-icons/bs"; import { BsGearFill, BsGithub, BsPersonCircle } from "react-icons/bs";
import { RiDatabase2Line, RiFlaskLine } from "react-icons/ri"; import { RiDatabase2Line, RiFlaskLine } from "react-icons/ri";
import { signIn, useSession } from "next-auth/react"; import { signIn, useSession } from "next-auth/react";
import UserMenu from "./UserMenu"; import UserMenu from "./UserMenu";
@@ -76,6 +76,21 @@ const NavSidebar = () => {
</NavSidebarOption> </NavSidebarOption>
)} )}
</VStack> </VStack>
<VStack w="full" alignItems="flex-start" spacing={0}>
<Text
pl={2}
pb={2}
fontSize="xs"
fontWeight="bold"
color="gray.500"
display={{ base: "none", md: "flex" }}
>
CONFIGURATION
</Text>
<NavSidebarOption activeHrefPattern="/settings">
<IconLink icon={BsGearFill} label="Project Settings" href="/settings" />
</NavSidebarOption>
</VStack>
{user && <UserMenu user={user} borderColor={"gray.200"} />} {user && <UserMenu user={user} borderColor={"gray.200"} />}
<Divider /> <Divider />
<VStack spacing={0} align="center"> <VStack spacing={0} align="center">

View File

@@ -0,0 +1,15 @@
import { Flex, type FlexProps } from "@chakra-ui/react";
const PageHeaderContainer = (props: FlexProps) => {
return <Flex
px={8}
py={2}
w="full"
direction={{ base: "column", sm: "row" }}
alignItems={{ base: "flex-start", sm: "center" }}
justifyContent="space-between"
{...props}
/>;
};
export default PageHeaderContainer;

View File

@@ -8,7 +8,6 @@ import {
PopoverTrigger, PopoverTrigger,
PopoverContent, PopoverContent,
Link, Link,
useColorMode,
type StackProps, type StackProps,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import { type Session } from "next-auth"; import { type Session } from "next-auth";
@@ -17,7 +16,6 @@ import { BsBoxArrowRight, BsChevronRight, BsPersonCircle } from "react-icons/bs"
import NavSidebarOption from "./NavSidebarOption"; import NavSidebarOption from "./NavSidebarOption";
export default function UserMenu({ user, ...rest }: { user: Session } & StackProps) { export default function UserMenu({ user, ...rest }: { user: Session } & StackProps) {
const { colorMode } = useColorMode();
const profileImage = user.user.image ? ( const profileImage = user.user.image ? (
<Image src={user.user.image} alt="profile picture" boxSize={8} borderRadius="50%" /> <Image src={user.user.image} alt="profile picture" boxSize={8} borderRadius="50%" />
@@ -28,17 +26,6 @@ export default function UserMenu({ user, ...rest }: { user: Session } & StackPro
return ( return (
<> <>
<Popover placement="right"> <Popover placement="right">
<VStack w="full" alignItems="flex-start" spacing={0} {...rest}>
<Text
pl={2}
pb={2}
fontSize="xs"
fontWeight="bold"
color="gray.500"
display={{ base: "none", md: "flex" }}
>
ACCOUNT
</Text>
<PopoverTrigger> <PopoverTrigger>
<NavSidebarOption> <NavSidebarOption>
<HStack <HStack
@@ -46,6 +33,7 @@ export default function UserMenu({ user, ...rest }: { user: Session } & StackPro
py={2} py={2}
px={1} px={1}
spacing={3} spacing={3}
{...rest}
> >
{profileImage} {profileImage}
<VStack spacing={0} align="start" flex={1} flexShrink={1}> <VStack spacing={0} align="start" flex={1} flexShrink={1}>
@@ -60,7 +48,6 @@ export default function UserMenu({ user, ...rest }: { user: Session } & StackPro
</HStack> </HStack>
</NavSidebarOption> </NavSidebarOption>
</PopoverTrigger> </PopoverTrigger>
</VStack>
<PopoverContent _focusVisible={{ boxShadow: "unset", outline: "unset" }} maxW="200px"> <PopoverContent _focusVisible={{ boxShadow: "unset", outline: "unset" }} maxW="200px">
<VStack align="stretch" spacing={0}> <VStack align="stretch" spacing={0}>
{/* sign out */} {/* sign out */}

View File

@@ -18,6 +18,7 @@ import { api } from "~/utils/api";
import { useDataset, useHandledAsyncCallback } from "~/utils/hooks"; import { useDataset, useHandledAsyncCallback } from "~/utils/hooks";
import DatasetEntriesTable from "~/components/datasets/DatasetEntriesTable"; import DatasetEntriesTable from "~/components/datasets/DatasetEntriesTable";
import { DatasetHeaderButtons } from "~/components/datasets/DatasetHeaderButtons/DatasetHeaderButtons"; import { DatasetHeaderButtons } from "~/components/datasets/DatasetHeaderButtons/DatasetHeaderButtons";
import PageHeaderContainer from "~/components/nav/PageHeaderContainer";
export default function Dataset() { export default function Dataset() {
const router = useRouter(); const router = useRouter();
@@ -55,14 +56,8 @@ export default function Dataset() {
return ( return (
<AppShell title={dataset.data?.name}> <AppShell title={dataset.data?.name}>
<VStack h="full"> <VStack h="full">
<Flex <PageHeaderContainer>
px={8} <Breadcrumb>
py={2}
w="full"
direction={{ base: "column", sm: "row" }}
alignItems={{ base: "flex-start", sm: "center" }}
>
<Breadcrumb flex={1} mt={1}>
<BreadcrumbItem> <BreadcrumbItem>
<Link href="/data"> <Link href="/data">
<Flex alignItems="center" _hover={{ textDecoration: "underline" }}> <Flex alignItems="center" _hover={{ textDecoration: "underline" }}>
@@ -88,7 +83,7 @@ export default function Dataset() {
</BreadcrumbItem> </BreadcrumbItem>
</Breadcrumb> </Breadcrumb>
<DatasetHeaderButtons /> <DatasetHeaderButtons />
</Flex> </PageHeaderContainer>
<Box w="full" overflowX="auto" flex={1} px={8} pt={8} pb={16}> <Box w="full" overflowX="auto" flex={1} px={8} pt={8} pb={16}>
{datasetId && <DatasetEntriesTable />} {datasetId && <DatasetEntriesTable />}
</Box> </Box>

View File

@@ -1,14 +1,12 @@
import { import {
SimpleGrid, SimpleGrid,
Icon, Icon,
VStack,
Breadcrumb, Breadcrumb,
BreadcrumbItem, BreadcrumbItem,
Flex, Flex,
Center, Center,
Text, Text,
Link, Link,
HStack,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import AppShell from "~/components/nav/AppShell"; import AppShell from "~/components/nav/AppShell";
import { api } from "~/utils/api"; import { api } from "~/utils/api";
@@ -19,6 +17,7 @@ import {
DatasetCardSkeleton, DatasetCardSkeleton,
NewDatasetCard, NewDatasetCard,
} from "~/components/datasets/DatasetCard"; } from "~/components/datasets/DatasetCard";
import PageHeaderContainer from "~/components/nav/PageHeaderContainer";
export default function DatasetsPage() { export default function DatasetsPage() {
const datasets = api.datasets.list.useQuery(); const datasets = api.datasets.list.useQuery();
@@ -50,17 +49,16 @@ export default function DatasetsPage() {
return ( return (
<AppShell title="Data"> <AppShell title="Data">
<VStack alignItems={"flex-start"} px={8} py={2}> <PageHeaderContainer>
<HStack minH={8} align="center" pt={2}> <Breadcrumb>
<Breadcrumb flex={1}> <BreadcrumbItem minH={8}>
<BreadcrumbItem>
<Flex alignItems="center"> <Flex alignItems="center">
<Icon as={RiDatabase2Line} boxSize={4} mr={2} /> Datasets <Icon as={RiDatabase2Line} boxSize={4} mr={2} /> Datasets
</Flex> </Flex>
</BreadcrumbItem> </BreadcrumbItem>
</Breadcrumb> </Breadcrumb>
</HStack> </PageHeaderContainer>
<SimpleGrid w="full" columns={{ base: 1, md: 2, lg: 3, xl: 4 }} spacing={8} py="4"> <SimpleGrid w="full" columns={{ base: 1, md: 2, lg: 3, xl: 4 }} spacing={8} py={4} px={8}>
<NewDatasetCard /> <NewDatasetCard />
{datasets.data && !datasets.isLoading ? ( {datasets.data && !datasets.isLoading ? (
datasets?.data?.map((dataset) => ( datasets?.data?.map((dataset) => (
@@ -77,7 +75,6 @@ export default function DatasetsPage() {
</> </>
)} )}
</SimpleGrid> </SimpleGrid>
</VStack>
</AppShell> </AppShell>
); );
} }

View File

@@ -23,6 +23,7 @@ import { useAppStore } from "~/state/store";
import { useSyncVariantEditor } from "~/state/sync"; import { useSyncVariantEditor } from "~/state/sync";
import { ExperimentHeaderButtons } from "~/components/experiments/ExperimentHeaderButtons/ExperimentHeaderButtons"; import { ExperimentHeaderButtons } from "~/components/experiments/ExperimentHeaderButtons/ExperimentHeaderButtons";
import Head from "next/head"; import Head from "next/head";
import PageHeaderContainer from "~/components/nav/PageHeaderContainer";
// TODO: import less to fix deployment with server side props // TODO: import less to fix deployment with server side props
// export const getServerSideProps = async (context: GetServerSidePropsContext<{ id: string }>) => { // export const getServerSideProps = async (context: GetServerSidePropsContext<{ id: string }>) => {
@@ -104,15 +105,8 @@ export default function Experiment() {
)} )}
<AppShell title={experiment.data?.label}> <AppShell title={experiment.data?.label}>
<VStack h="full"> <VStack h="full">
<Flex <PageHeaderContainer>
pl={8} <Breadcrumb>
pr={4}
py={2}
w="full"
direction={{ base: "column", sm: "row" }}
alignItems={{ base: "flex-start", sm: "center" }}
>
<Breadcrumb flex={1}>
<BreadcrumbItem> <BreadcrumbItem>
<Link href="/experiments"> <Link href="/experiments">
<Flex alignItems="center" _hover={{ textDecoration: "underline" }}> <Flex alignItems="center" _hover={{ textDecoration: "underline" }}>
@@ -144,7 +138,7 @@ export default function Experiment() {
</BreadcrumbItem> </BreadcrumbItem>
</Breadcrumb> </Breadcrumb>
<ExperimentHeaderButtons /> <ExperimentHeaderButtons />
</Flex> </PageHeaderContainer>
<ExperimentSettingsDrawer /> <ExperimentSettingsDrawer />
<Box w="100%" overflowX="auto" flex={1}> <Box w="100%" overflowX="auto" flex={1}>
<OutputsTable experimentId={router.query.id as string | undefined} /> <OutputsTable experimentId={router.query.id as string | undefined} />

View File

@@ -1,14 +1,12 @@
import { import {
SimpleGrid, SimpleGrid,
Icon, Icon,
VStack,
Breadcrumb, Breadcrumb,
BreadcrumbItem, BreadcrumbItem,
Flex, Flex,
Center, Center,
Text, Text,
Link, Link,
HStack,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import { RiFlaskLine } from "react-icons/ri"; import { RiFlaskLine } from "react-icons/ri";
import AppShell from "~/components/nav/AppShell"; import AppShell from "~/components/nav/AppShell";
@@ -19,6 +17,7 @@ import {
NewExperimentCard, NewExperimentCard,
} from "~/components/experiments/ExperimentCard"; } from "~/components/experiments/ExperimentCard";
import { signIn, useSession } from "next-auth/react"; import { signIn, useSession } from "next-auth/react";
import PageHeaderContainer from "~/components/nav/PageHeaderContainer";
export default function ExperimentsPage() { export default function ExperimentsPage() {
const experiments = api.experiments.list.useQuery(); const experiments = api.experiments.list.useQuery();
@@ -50,17 +49,16 @@ export default function ExperimentsPage() {
return ( return (
<AppShell title="Experiments"> <AppShell title="Experiments">
<VStack alignItems={"flex-start"} px={8} py={2}> <PageHeaderContainer>
<HStack minH={8} align="center" pt={2}> <Breadcrumb>
<Breadcrumb flex={1}> <BreadcrumbItem minH={8}>
<BreadcrumbItem>
<Flex alignItems="center"> <Flex alignItems="center">
<Icon as={RiFlaskLine} boxSize={4} mr={2} /> Experiments <Icon as={RiFlaskLine} boxSize={4} mr={2} /> Experiments
</Flex> </Flex>
</BreadcrumbItem> </BreadcrumbItem>
</Breadcrumb> </Breadcrumb>
</HStack> </PageHeaderContainer>
<SimpleGrid w="full" columns={{ base: 1, md: 2, lg: 3, xl: 4 }} spacing={8} py="4"> <SimpleGrid w="full" columns={{ base: 1, md: 2, lg: 3, xl: 4 }} spacing={8} py="4" px={8}>
<NewExperimentCard /> <NewExperimentCard />
{experiments.data && !experiments.isLoading ? ( {experiments.data && !experiments.isLoading ? (
experiments?.data?.map((exp) => <ExperimentCard key={exp.id} exp={exp} />) experiments?.data?.map((exp) => <ExperimentCard key={exp.id} exp={exp} />)
@@ -72,7 +70,6 @@ export default function ExperimentsPage() {
</> </>
)} )}
</SimpleGrid> </SimpleGrid>
</VStack>
</AppShell> </AppShell>
); );
} }

View File

@@ -1,6 +1,7 @@
import { Breadcrumb, BreadcrumbItem, HStack, Input } from "@chakra-ui/react"; import { Breadcrumb, BreadcrumbItem, Input } from "@chakra-ui/react";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import AppShell from "~/components/nav/AppShell"; import AppShell from "~/components/nav/AppShell";
import PageHeaderContainer from "~/components/nav/PageHeaderContainer";
import { api } from "~/utils/api"; import { api } from "~/utils/api";
import { useHandledAsyncCallback, useSelectedOrg } from "~/utils/hooks"; import { useHandledAsyncCallback, useSelectedOrg } from "~/utils/hooks";
@@ -25,13 +26,7 @@ export default function HomePage() {
}, [selectedOrg?.name]); }, [selectedOrg?.name]);
return ( return (
<AppShell> <AppShell>
<HStack <PageHeaderContainer>
px={4}
py={2}
w="full"
direction={{ base: "column", sm: "row" }}
alignItems={{ base: "flex-start", sm: "center" }}
>
<Breadcrumb flex={1}> <Breadcrumb flex={1}>
<BreadcrumbItem isCurrentPage> <BreadcrumbItem isCurrentPage>
<Input <Input
@@ -50,7 +45,7 @@ export default function HomePage() {
/> />
</BreadcrumbItem> </BreadcrumbItem>
</Breadcrumb> </Breadcrumb>
</HStack> </PageHeaderContainer>
</AppShell> </AppShell>
); );
} }

View File

@@ -0,0 +1,52 @@
import { Breadcrumb, BreadcrumbItem, Input } from "@chakra-ui/react";
import { useEffect, useState } from "react";
import AppShell from "~/components/nav/AppShell";
import PageHeaderContainer from "~/components/nav/PageHeaderContainer";
import { api } from "~/utils/api";
import { useHandledAsyncCallback, useSelectedOrg } from "~/utils/hooks";
export default function Settings() {
const utils = api.useContext();
const { data: selectedOrg } = useSelectedOrg();
const updateMutation = api.organizations.update.useMutation();
const [onSaveName] = useHandledAsyncCallback(async () => {
if (name && name !== selectedOrg?.name && selectedOrg?.id) {
await updateMutation.mutateAsync({
id: selectedOrg.id,
updates: { name },
});
await Promise.all([utils.organizations.get.invalidate({ id: selectedOrg.id })]);
}
}, [updateMutation, selectedOrg]);
const [name, setName] = useState(selectedOrg?.name);
useEffect(() => {
setName(selectedOrg?.name);
}, [selectedOrg?.name]);
return (
<AppShell>
<PageHeaderContainer>
<Breadcrumb>
<BreadcrumbItem isCurrentPage>
<Input
size="sm"
value={name}
onChange={(e) => setName(e.target.value)}
onBlur={onSaveName}
borderWidth={1}
borderColor="transparent"
fontSize={16}
px={0}
minW={{ base: 100, lg: 300 }}
flex={1}
_hover={{ borderColor: "gray.300" }}
_focus={{ borderColor: "blue.500", outline: "none" }}
/>
</BreadcrumbItem>
</Breadcrumb>
</PageHeaderContainer>
</AppShell>
);
}