experiment page visual tweaks

This commit is contained in:
Kyle Corbitt
2023-07-18 22:22:58 -07:00
parent 1c1cefe286
commit 2cb623f332
5 changed files with 44 additions and 66 deletions

View File

@@ -7,11 +7,16 @@ import {
Text,
CardHeader,
Divider,
Box,
Spinner,
AspectRatio,
} from "@chakra-ui/react";
import { RiFlaskLine } from "react-icons/ri";
import { formatTimePast } from "~/utils/dayjs";
import Link from "next/link";
import { useRouter } from "next/router";
import { BsPlusSquare } from "react-icons/bs";
import { api } from "~/utils/api";
import { useHandledAsyncCallback } from "~/utils/hooks";
type ExperimentData = {
testScenarioCount: number;
@@ -24,24 +29,17 @@ type ExperimentData = {
};
export const ExperimentCard = ({ exp }: { exp: ExperimentData }) => {
const router = useRouter();
return (
<Box
as={Card}
variant="elevated"
<Card
as={Link}
bg="gray.50"
_hover={{ bg: "gray.100" }}
transition="background 0.2s"
cursor="pointer"
onClick={(e) => {
e.preventDefault();
void router.push({ pathname: "/experiments/[id]", query: { id: exp.id } }, undefined, {
shallow: true,
});
}}
href={{ pathname: "/experiments/[id]", query: { id: exp.id } }}
>
<CardHeader>
<HStack w="full" color="gray.700">
<HStack w="full" color="gray.700" justify="center">
<Icon as={RiFlaskLine} boxSize={4} />
<Text fontWeight="bold">{exp.label}</Text>
</HStack>
@@ -52,19 +50,19 @@ export const ExperimentCard = ({ exp }: { exp: ExperimentData }) => {
<Divider h={12} orientation="vertical" />
<CountLabel label="Scenarios" count={exp.testScenarioCount} />
</HStack>
<HStack w="full" color="gray.500" fontSize="xs">
<Text>Created {formatTimePast(exp.createdAt)}</Text>
<HStack w="full" color="gray.500" fontSize="xs" textAlign="center">
<Text flex={1}>Created {formatTimePast(exp.createdAt)}</Text>
<Divider h={4} orientation="vertical" />
<Text>Updated {formatTimePast(exp.updatedAt)}</Text>
<Text flex={1}>Updated {formatTimePast(exp.updatedAt)}</Text>
</HStack>
</CardBody>
</Box>
</Card>
);
};
const CountLabel = ({ label, count }: { label: string; count: number }) => {
return (
<VStack alignItems="flex-start">
<VStack alignItems="center" flex={1}>
<Text color="gray.500" fontWeight="bold">
{label}
</Text>
@@ -74,3 +72,26 @@ const CountLabel = ({ label, count }: { label: string; count: number }) => {
</VStack>
);
};
export const NewExperimentCard = () => {
const router = useRouter();
const utils = api.useContext();
const createMutation = api.experiments.create.useMutation();
const [createExperiment, isLoading] = useHandledAsyncCallback(async () => {
const newExperiment = await createMutation.mutateAsync({ label: "New Experiment" });
await router.push({ pathname: "/experiments/[id]", query: { id: newExperiment.id } });
}, [createMutation, router]);
return (
<Card _hover={{ cursor: "pointer", bgColor: "gray.50" }} onClick={createExperiment}>
<AspectRatio ratio={1} w="full">
<VStack align="center" justify="center" h="100%" spacing={6}>
<Icon as={isLoading ? Spinner : BsPlusSquare} boxSize={8} />
<Text display={{ base: "none", md: "block" }} ml={2}>
New Experiment
</Text>
</VStack>
</AspectRatio>
</Card>
);
};

View File

@@ -1,31 +0,0 @@
import { Icon, Button, Spinner, Text, type ButtonProps } from "@chakra-ui/react";
import { api } from "~/utils/api";
import { useRouter } from "next/router";
import { BsPlusSquare } from "react-icons/bs";
import { useHandledAsyncCallback } from "~/utils/hooks";
export const NewExperimentButton = (props: ButtonProps) => {
const router = useRouter();
const utils = api.useContext();
const createMutation = api.experiments.create.useMutation();
const [createExperiment, isLoading] = useHandledAsyncCallback(async () => {
const newExperiment = await createMutation.mutateAsync({ label: "New Experiment" });
await utils.experiments.list.invalidate();
await router.push({ pathname: "/experiments/[id]", query: { id: newExperiment.id } });
}, [createMutation, router]);
return (
<Button
onClick={createExperiment}
display="flex"
alignItems="center"
variant={{ base: "solid", md: "ghost" }}
{...props}
>
<Icon as={isLoading ? Spinner : BsPlusSquare} boxSize={4} />
<Text display={{ base: "none", md: "block" }} ml={2}>
New Experiment
</Text>
</Button>
);
};

View File

@@ -13,8 +13,7 @@ import {
import { RiFlaskLine } from "react-icons/ri";
import AppShell from "~/components/nav/AppShell";
import { api } from "~/utils/api";
import { NewExperimentButton } from "~/components/experiments/NewExperimentButton";
import { ExperimentCard } from "~/components/experiments/ExperimentCard";
import { ExperimentCard, NewExperimentCard } from "~/components/experiments/ExperimentCard";
import { signIn, useSession } from "next-auth/react";
export default function ExperimentsPage() {
@@ -45,7 +44,7 @@ export default function ExperimentsPage() {
return (
<AppShell title="Experiments">
<VStack alignItems={"flex-start"} m={4} mt={1}>
<HStack w="full" justifyContent="space-between" mb={4}>
<HStack w="full" mb={4}>
<Breadcrumb flex={1}>
<BreadcrumbItem>
<Flex alignItems="center">
@@ -53,9 +52,9 @@ export default function ExperimentsPage() {
</Flex>
</BreadcrumbItem>
</Breadcrumb>
<NewExperimentButton mr={4} borderRadius={8} />
</HStack>
<SimpleGrid w="full" columns={{ base: 1, md: 2, lg: 3, xl: 4 }} spacing={8} p="4">
<NewExperimentCard />
{experiments?.data?.map((exp) => <ExperimentCard key={exp.id} exp={exp} />)}
</SimpleGrid>
</VStack>

View File

@@ -25,7 +25,7 @@ export const experimentsRouter = createTRPCRouter({
},
},
orderBy: {
sortIndex: "asc",
sortIndex: "desc",
},
});

View File

@@ -5,16 +5,5 @@ import relativeTime from "dayjs/plugin/relativeTime";
dayjs.extend(duration);
dayjs.extend(relativeTime);
export const formatTimePast = (date: Date) => {
const now = dayjs();
const dayDiff = Math.floor(now.diff(date, "day"));
if (dayDiff > 0) return dayjs.duration(-dayDiff, "days").humanize(true);
const hourDiff = Math.floor(now.diff(date, "hour"));
if (hourDiff > 0) return dayjs.duration(-hourDiff, "hours").humanize(true);
const minuteDiff = Math.floor(now.diff(date, "minute"));
if (minuteDiff > 0) return dayjs.duration(-minuteDiff, "minutes").humanize(true);
return "a few seconds ago";
};
export const formatTimePast = (date: Date) =>
dayjs.duration(dayjs(date).diff(dayjs())).humanize(true);