ripped out mantine, replaced with chakra

This commit is contained in:
Kyle Corbitt
2023-06-23 17:23:30 -07:00
parent 5fcefad461
commit c497b74208
12 changed files with 1331 additions and 647 deletions

View File

@@ -11,14 +11,11 @@
"start": "next start" "start": "next start"
}, },
"dependencies": { "dependencies": {
"@chakra-ui/next-js": "^2.1.4",
"@chakra-ui/react": "^2.7.1",
"@emotion/react": "^11.11.1", "@emotion/react": "^11.11.1",
"@emotion/server": "^11.11.0", "@emotion/server": "^11.11.0",
"@mantine/core": "^6.0.14", "@emotion/styled": "^11.11.0",
"@mantine/dates": "^6.0.14",
"@mantine/form": "^6.0.14",
"@mantine/hooks": "^6.0.14",
"@mantine/next": "^6.0.14",
"@mantine/notifications": "^6.0.14",
"@monaco-editor/react": "^4.5.1", "@monaco-editor/react": "^4.5.1",
"@next-auth/prisma-adapter": "^1.0.5", "@next-auth/prisma-adapter": "^1.0.5",
"@prisma/client": "^4.14.0", "@prisma/client": "^4.14.0",
@@ -31,6 +28,7 @@
"@trpc/server": "^10.26.0", "@trpc/server": "^10.26.0",
"dayjs": "^1.11.8", "dayjs": "^1.11.8",
"dotenv": "^16.3.1", "dotenv": "^16.3.1",
"framer-motion": "^10.12.17",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"next": "^13.4.2", "next": "^13.4.2",
"next-auth": "^4.22.1", "next-auth": "^4.22.1",

1730
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,8 @@
import { useRef } from "react"; import { useRef } from "react";
import { Title } from "@mantine/core";
import { type PromptVariant } from "./types"; import { type PromptVariant } from "./types";
import { api } from "~/utils/api"; import { api } from "~/utils/api";
import { useHandledAsyncCallback } from "~/utils/hooks"; import { useHandledAsyncCallback } from "~/utils/hooks";
import { Heading } from "@chakra-ui/react";
export default function EditableVariantLabel(props: { variant: PromptVariant }) { export default function EditableVariantLabel(props: { variant: PromptVariant }) {
const labelRef = useRef<HTMLHeadingElement | null>(null); const labelRef = useRef<HTMLHeadingElement | null>(null);
@@ -20,8 +20,15 @@ export default function EditableVariantLabel(props: { variant: PromptVariant })
}, [mutation, props.variant.id, props.variant.label]); }, [mutation, props.variant.id, props.variant.label]);
return ( return (
<Title order={4} ref={labelRef} contentEditable suppressContentEditableWarning onBlur={onBlur}> <Heading
fontWeight="bold"
size="md"
ref={labelRef}
contentEditable
suppressContentEditableWarning
onBlur={onBlur}
>
{props.variant.label} {props.variant.label}
</Title> </Heading>
); );
} }

View File

@@ -1,6 +1,6 @@
import { api } from "~/utils/api"; import { api } from "~/utils/api";
import { PromptVariant, Scenario } from "./types"; import { PromptVariant, Scenario } from "./types";
import { Center } from "@mantine/core"; import { Center } from "@chakra-ui/react";
export default function OutputCell({ export default function OutputCell({
scenario, scenario,

View File

@@ -1,9 +1,9 @@
import { api } from "~/utils/api"; import { api } from "~/utils/api";
import { isEqual } from "lodash"; import { isEqual } from "lodash";
import { PromptVariant, Scenario } from "./types"; import { PromptVariant, Scenario } from "./types";
import { Badge, Button, Group, Stack, TextInput, Textarea, Tooltip } from "@mantine/core";
import { useExperiment, useHandledAsyncCallback } from "~/utils/hooks"; import { useExperiment, useHandledAsyncCallback } from "~/utils/hooks";
import { useState } from "react"; import { useState } from "react";
import { Badge, Button, Flex, HStack, Stack, Textarea } from "@chakra-ui/react";
export default function ScenarioHeader({ scenario }: { scenario: Scenario }) { export default function ScenarioHeader({ scenario }: { scenario: Scenario }) {
const savedValues = scenario.variableValues as Record<string, string>; const savedValues = scenario.variableValues as Record<string, string>;
@@ -31,21 +31,23 @@ export default function ScenarioHeader({ scenario }: { scenario: Scenario }) {
<Stack> <Stack>
{variableLabels.map((key) => { {variableLabels.map((key) => {
return ( return (
<Textarea <Flex key={key}>
key={key} <Badge>{key}</Badge>
label={key} <Textarea
value={values[key] ?? ""} key={key}
onChange={(e) => { value={values[key] ?? ""}
setValues((prev) => ({ ...prev, [key]: e.target.value })); onChange={(e) => {
}} setValues((prev) => ({ ...prev, [key]: e.target.value }));
autosize }}
rows={1} rows={1}
maxRows={20} // TODO: autosize
/> maxRows={20}
/>
</Flex>
); );
})} })}
{hasChanged && ( {hasChanged && (
<Group spacing={4} position="right"> <HStack spacing={4}>
<Button <Button
size="xs" size="xs"
onClick={() => { onClick={() => {
@@ -58,7 +60,7 @@ export default function ScenarioHeader({ scenario }: { scenario: Scenario }) {
<Button size="xs" onClick={onSave}> <Button size="xs" onClick={onSave}>
Save Save
</Button> </Button>
</Group> </HStack>
)} )}
</Stack> </Stack>
); );

View File

@@ -1,7 +1,6 @@
import { Box, Button, Group, Stack, Title, Tooltip } from "@mantine/core"; import { Box, Button, HStack, Tooltip } from "@chakra-ui/react";
import { useMonaco } from "@monaco-editor/react"; import { useMonaco } from "@monaco-editor/react";
import { useRef, useEffect, useState, useCallback } from "react"; import { useRef, useEffect, useState, useCallback } from "react";
import { set } from "zod";
import { useHandledAsyncCallback, useModifierKeyLabel } from "~/utils/hooks"; import { useHandledAsyncCallback, useModifierKeyLabel } from "~/utils/hooks";
let isThemeDefined = false; let isThemeDefined = false;
@@ -109,23 +108,23 @@ export default function VariantConfigEditor(props: {
<Box w="100%" pos="relative"> <Box w="100%" pos="relative">
<div id={editorId} style={{ height: "300px", width: "100%" }}></div> <div id={editorId} style={{ height: "300px", width: "100%" }}></div>
{isChanged && ( {isChanged && (
<Group sx={{ position: "absolute", bottom: 0, right: 0 }} spacing={4}> <HStack pos="absolute" bottom={0} right={0} spacing={4}>
<Button <Button
colorScheme="gray"
size="xs" size="xs"
onClick={() => { onClick={() => {
editorRef.current?.setValue(props.savedConfig); editorRef.current?.setValue(props.savedConfig);
checkForChanges(); checkForChanges();
}} }}
color="gray"
> >
Reset Reset
</Button> </Button>
<Tooltip label={`${modifierKey} + Enter`} withArrow> <Tooltip label={`${modifierKey} + Enter`}>
<Button size="xs" onClick={onSave}> <Button size="xs" onClick={onSave} colorScheme="blue">
Save Save
</Button> </Button>
</Tooltip> </Tooltip>
</Group> </HStack>
)} )}
</Box> </Box>
); );

View File

@@ -1,15 +1,15 @@
import { Stack, Title } from "@mantine/core";
import { useCallback } from "react"; import { useCallback } from "react";
import type { PromptVariant } from "./types"; import type { PromptVariant } from "./types";
import { api } from "~/utils/api"; import { api } from "~/utils/api";
import { notifications } from "@mantine/notifications";
import { type JSONSerializable } from "~/server/types"; import { type JSONSerializable } from "~/server/types";
import VariantConfigEditor from "./VariantConfigEditor"; import VariantConfigEditor from "./VariantConfigEditor";
import EditableVariantLabel from "./EditableVariantLabel"; import EditableVariantLabel from "./EditableVariantLabel";
import { Stack, useToast } from "@chakra-ui/react";
export default function VariantHeader({ variant }: { variant: PromptVariant }) { export default function VariantHeader({ variant }: { variant: PromptVariant }) {
const replaceWithConfig = api.promptVariants.replaceWithConfig.useMutation(); const replaceWithConfig = api.promptVariants.replaceWithConfig.useMutation();
const utils = api.useContext(); const utils = api.useContext();
const toast = useToast();
const onSave = useCallback( const onSave = useCallback(
async (currentConfig: string) => { async (currentConfig: string) => {
@@ -17,10 +17,12 @@ export default function VariantHeader({ variant }: { variant: PromptVariant }) {
try { try {
parsedConfig = JSON.parse(currentConfig) as JSONSerializable; parsedConfig = JSON.parse(currentConfig) as JSONSerializable;
} catch (e) { } catch (e) {
notifications.show({ toast({
title: "Invalid JSON", title: "Invalid JSON",
message: "Please fix the JSON before saving.", description: "Please fix the JSON before saving.",
color: "red", status: "error",
duration: 5000,
position: "top",
}); });
return; return;
} }

View File

@@ -4,11 +4,11 @@ import { type PromptVariant } from "./types";
import VariantHeader from "./VariantHeader"; import VariantHeader from "./VariantHeader";
import OutputCell from "./OutputCell"; import OutputCell from "./OutputCell";
import ScenarioHeader from "./ScenarioHeader"; import ScenarioHeader from "./ScenarioHeader";
import { Box, Header, Title } from "@mantine/core";
import React from "react"; import React from "react";
import { Box, Heading } from "@chakra-ui/react";
const cellPaddingX = 8; const cellPaddingX = 4;
const cellPaddingY = 4; const cellPaddingY = 2;
export default function OutputsTable({ experimentId }: { experimentId: string | undefined }) { export default function OutputsTable({ experimentId }: { experimentId: string | undefined }) {
const variants = api.promptVariants.list.useQuery( const variants = api.promptVariants.list.useQuery(
@@ -24,7 +24,7 @@ export default function OutputsTable({ experimentId }: { experimentId: string |
if (!variants.data || !scenarios.data) return null; if (!variants.data || !scenarios.data) return null;
return ( return (
<Box p={12}> <Box p={4}>
<div <div
style={{ style={{
display: "grid", display: "grid",
@@ -33,7 +33,9 @@ export default function OutputsTable({ experimentId }: { experimentId: string |
}} }}
> >
<Box px={cellPaddingX} py={cellPaddingY} display="flex" sx={{}}> <Box px={cellPaddingX} py={cellPaddingY} display="flex" sx={{}}>
<Title order={4}>Scenario</Title> <Heading size="md" fontWeight="bold">
Scenario
</Heading>
</Box> </Box>
{variants.data.map((variant) => ( {variants.data.map((variant) => (
<Box key={variant.uiId} px={cellPaddingX} py={cellPaddingY}> <Box key={variant.uiId} px={cellPaddingX} py={cellPaddingY}>

View File

@@ -1,129 +1,15 @@
import { useState } from "react"; import { Box, Flex } from "@chakra-ui/react";
import { createStyles, Navbar, Group, Code, getStylesRef, rem, Box } from "@mantine/core";
import {
IconBellRinging,
IconFingerprint,
IconKey,
IconSettings,
Icon2fa,
IconDatabaseImport,
IconReceipt2,
IconSwitchHorizontal,
IconLogout,
} from "@tabler/icons-react";
import Head from "next/head"; import Head from "next/head";
// import { MantineLogo } from '@mantine/ds';
const useStyles = createStyles((theme) => ({
header: {
paddingBottom: theme.spacing.md,
marginBottom: `calc(${theme.spacing.md} * 1.5)`,
borderBottom: `${rem(1)} solid ${
theme.colorScheme === "dark" ? theme.colors.dark[4] : theme.colors.gray[4]
}`,
},
footer: {
paddingTop: theme.spacing.md,
marginTop: theme.spacing.md,
borderTop: `${rem(1)} solid ${
theme.colorScheme === "dark" ? theme.colors.dark[4] : theme.colors.gray[4]
}`,
},
link: {
...(theme.fn.focusStyles() as Record<string, any>),
display: "flex",
alignItems: "center",
textDecoration: "none",
fontSize: theme.fontSizes.sm,
color: theme.colorScheme === "dark" ? theme.colors.dark[1] : theme.colors.gray[7],
padding: `${theme.spacing.xs} ${theme.spacing.sm}`,
borderRadius: theme.radius.sm,
fontWeight: 500,
"&:hover": {
backgroundColor: theme.colorScheme === "dark" ? theme.colors.dark[6] : theme.colors.gray[0],
color: theme.colorScheme === "dark" ? theme.white : theme.black,
[`& .${getStylesRef("icon")}`]: {
color: theme.colorScheme === "dark" ? theme.white : theme.black,
},
},
},
linkIcon: {
ref: getStylesRef("icon"),
color: theme.colorScheme === "dark" ? theme.colors.dark[2] : theme.colors.gray[6],
marginRight: theme.spacing.sm,
},
linkActive: {
"&, &:hover": {
backgroundColor: theme.fn.variant({ variant: "dark", color: theme.primaryColor }).background,
color: theme.fn.variant({ variant: "dark", color: theme.primaryColor }).color,
[`& .${getStylesRef("icon")}`]: {
color: theme.fn.variant({ variant: "dark", color: theme.primaryColor }).color,
},
},
},
}));
const data = [
{ link: "", label: "Notifications", icon: IconBellRinging },
{ link: "", label: "Billing", icon: IconReceipt2 },
{ link: "", label: "Security", icon: IconFingerprint },
{ link: "", label: "SSH Keys", icon: IconKey },
{ link: "", label: "Databases", icon: IconDatabaseImport },
{ link: "", label: "Authentication", icon: Icon2fa },
{ link: "", label: "Other Settings", icon: IconSettings },
];
export default function AppNav(props: { children: React.ReactNode; title?: string }) { export default function AppNav(props: { children: React.ReactNode; title?: string }) {
const { classes, cx } = useStyles();
const [active, setActive] = useState("Billing");
const links = data.map((item) => (
<a
className={cx(classes.link, { [classes.linkActive]: item.label === active })}
href={item.link}
key={item.label}
onClick={(event) => {
event.preventDefault();
setActive(item.label);
}}
>
<item.icon className={classes.linkIcon} stroke={1.5} />
<span>{item.label}</span>
</a>
));
return ( return (
<Box mih="100vh" sx={{ display: "flex" }}> <Flex minH="100vh" align="stretch">
<Head> <Head>
<title>{props.title ? `${props.title} | Prompt Bench` : "Prompt Bench"}</title> <title>{props.title ? `${props.title} | Prompt Bench` : "Prompt Bench"}</title>
</Head> </Head>
<Navbar height="100vh" width={{ sm: 250 }} p="md" bg="gray.1"> {/* Placeholder for now */}
<Navbar.Section grow> <Box bgColor="gray.100" height="100vh" width="200px" />
<Group className={classes.header} position="apart"> <Box flex={1}>{props.children}</Box>
<Code sx={{ fontWeight: 700 }}>v3.1.2</Code> </Flex>
</Group>
{links}
</Navbar.Section>
<Navbar.Section className={classes.footer}>
<a href="#" className={classes.link} onClick={(event) => event.preventDefault()}>
<IconSwitchHorizontal className={classes.linkIcon} stroke={1.5} />
<span>Change account</span>
</a>
<a href="#" className={classes.link} onClick={(event) => event.preventDefault()}>
<IconLogout className={classes.linkIcon} stroke={1.5} />
<span>Logout</span>
</a>
</Navbar.Section>
</Navbar>
<Box sx={{ flex: 1 }}>{props.children}</Box>
</Box>
); );
} }

View File

@@ -2,8 +2,7 @@ import { type Session } from "next-auth";
import { SessionProvider } from "next-auth/react"; import { SessionProvider } from "next-auth/react";
import { type AppType } from "next/app"; import { type AppType } from "next/app";
import { api } from "~/utils/api"; import { api } from "~/utils/api";
import { MantineProvider } from "@mantine/core"; import { ChakraProvider } from "@chakra-ui/react";
import { Notifications } from "@mantine/notifications";
const MyApp: AppType<{ session: Session | null }> = ({ const MyApp: AppType<{ session: Session | null }> = ({
Component, Component,
@@ -11,10 +10,9 @@ const MyApp: AppType<{ session: Session | null }> = ({
}) => { }) => {
return ( return (
<SessionProvider session={session}> <SessionProvider session={session}>
<MantineProvider withGlobalStyles withNormalizeCSS> <ChakraProvider>
<Notifications position="bottom-center" />
<Component {...pageProps} /> <Component {...pageProps} />
</MantineProvider> </ChakraProvider>
</SessionProvider> </SessionProvider>
); );
}; };

View File

@@ -1,20 +0,0 @@
import { createGetInitialProps } from "@mantine/next";
import Document, { Head, Html, Main, NextScript } from "next/document";
const getInitialProps = createGetInitialProps();
export default class _Document extends Document {
static getInitialProps = getInitialProps;
render() {
return (
<Html>
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}

View File

@@ -1,4 +1,4 @@
import { Box, Center } from "@mantine/core"; import { Box, Center } from "@chakra-ui/react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import OutputsTable from "~/components/OutputsTable"; import OutputsTable from "~/components/OutputsTable";
import AppNav from "~/components/nav/AppNav"; import AppNav from "~/components/nav/AppNav";