add mantine
This commit is contained in:
@@ -11,9 +11,16 @@
|
||||
"start": "next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.11.1",
|
||||
"@emotion/server": "^11.11.0",
|
||||
"@mantine/core": "^6.0.14",
|
||||
"@mantine/form": "^6.0.14",
|
||||
"@mantine/hooks": "^6.0.14",
|
||||
"@mantine/next": "^6.0.14",
|
||||
"@next-auth/prisma-adapter": "^1.0.5",
|
||||
"@prisma/client": "^4.14.0",
|
||||
"@t3-oss/env-nextjs": "^0.3.1",
|
||||
"@tabler/icons-react": "^2.22.0",
|
||||
"@tanstack/react-query": "^4.29.7",
|
||||
"@trpc/client": "^10.26.0",
|
||||
"@trpc/next": "^10.26.0",
|
||||
|
||||
931
pnpm-lock.yaml
generated
931
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
126
src/components/nav/AppNav.tsx
Normal file
126
src/components/nav/AppNav.tsx
Normal file
@@ -0,0 +1,126 @@
|
||||
import { useState } from "react";
|
||||
import { createStyles, Navbar, Group, Code, getStylesRef, rem } from "@mantine/core";
|
||||
import {
|
||||
IconBellRinging,
|
||||
IconFingerprint,
|
||||
IconKey,
|
||||
IconSettings,
|
||||
Icon2fa,
|
||||
IconDatabaseImport,
|
||||
IconReceipt2,
|
||||
IconSwitchHorizontal,
|
||||
IconLogout,
|
||||
} from "@tabler/icons-react";
|
||||
// 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[2]
|
||||
}`,
|
||||
},
|
||||
|
||||
footer: {
|
||||
paddingTop: theme.spacing.md,
|
||||
marginTop: theme.spacing.md,
|
||||
borderTop: `${rem(1)} solid ${
|
||||
theme.colorScheme === "dark" ? theme.colors.dark[4] : theme.colors.gray[2]
|
||||
}`,
|
||||
},
|
||||
|
||||
link: {
|
||||
...theme.fn.focusStyles(),
|
||||
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: "light", color: theme.primaryColor }).background,
|
||||
color: theme.fn.variant({ variant: "light", color: theme.primaryColor }).color,
|
||||
[`& .${getStylesRef("icon")}`]: {
|
||||
color: theme.fn.variant({ variant: "light", 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({ children }: { children: React.ReactNode }) {
|
||||
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 (
|
||||
<Group h="100vh">
|
||||
<Navbar height="100%" width={{ sm: 300 }} p="md">
|
||||
<Navbar.Section grow>
|
||||
<Group className={classes.header} position="apart">
|
||||
{/* <MantineLogo size={28} /> */}
|
||||
<Code sx={{ fontWeight: 700 }}>v3.1.2</Code>
|
||||
</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>
|
||||
{children}
|
||||
</Group>
|
||||
);
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import { type Session } from "next-auth";
|
||||
import { SessionProvider } from "next-auth/react";
|
||||
import { type AppType } from "next/app";
|
||||
import { api } from "~/utils/api";
|
||||
import "~/styles/globals.css";
|
||||
import { MantineProvider } from "@mantine/core";
|
||||
|
||||
const MyApp: AppType<{ session: Session | null }> = ({
|
||||
Component,
|
||||
@@ -10,7 +10,9 @@ const MyApp: AppType<{ session: Session | null }> = ({
|
||||
}) => {
|
||||
return (
|
||||
<SessionProvider session={session}>
|
||||
<MantineProvider withGlobalStyles withNormalizeCSS>
|
||||
<Component {...pageProps} />
|
||||
</MantineProvider>
|
||||
</SessionProvider>
|
||||
);
|
||||
};
|
||||
|
||||
20
src/pages/_document.tsx
Normal file
20
src/pages/_document.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
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>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { createNextApiHandler } from "@trpc/server/adapters/next";
|
||||
import { env } from "~/env.mjs";
|
||||
import { appRouter } from "~/server/api/root";
|
||||
import { appRouter } from "~/server/api/root.router";
|
||||
import { createTRPCContext } from "~/server/api/trpc";
|
||||
|
||||
// export API handler
|
||||
@@ -10,9 +10,7 @@ export default createNextApiHandler({
|
||||
onError:
|
||||
env.NODE_ENV === "development"
|
||||
? ({ path, error }) => {
|
||||
console.error(
|
||||
`❌ tRPC failed on ${path ?? "<no-path>"}: ${error.message}`,
|
||||
);
|
||||
console.error(`❌ tRPC failed on ${path ?? "<no-path>"}: ${error.message}`);
|
||||
}
|
||||
: undefined,
|
||||
});
|
||||
|
||||
9
src/pages/experiments/[id].tsx
Normal file
9
src/pages/experiments/[id].tsx
Normal file
@@ -0,0 +1,9 @@
|
||||
import AppNav from "~/components/nav/AppNav";
|
||||
|
||||
export default function Experiment() {
|
||||
return (
|
||||
<AppNav>
|
||||
<div>test content</div>
|
||||
</AppNav>
|
||||
);
|
||||
}
|
||||
@@ -1,149 +0,0 @@
|
||||
.main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 100vh;
|
||||
background-image: linear-gradient(to bottom, #2e026d, #15162c);
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 3rem;
|
||||
padding: 4rem 1rem;
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.container {
|
||||
max-width: 640px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.container {
|
||||
max-width: 768px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.container {
|
||||
max-width: 1024px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1280px) {
|
||||
.container {
|
||||
max-width: 1280px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1536px) {
|
||||
.container {
|
||||
max-width: 1536px;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 3rem;
|
||||
line-height: 1;
|
||||
font-weight: 800;
|
||||
letter-spacing: -0.025em;
|
||||
margin: 0;
|
||||
color: white;
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.title {
|
||||
font-size: 5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.pinkSpan {
|
||||
color: hsl(280 100% 70%);
|
||||
}
|
||||
|
||||
.cardRow {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(1, minmax(0, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.cardRow {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.cardRow {
|
||||
gap: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
.card {
|
||||
max-width: 20rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
padding: 1rem;
|
||||
border-radius: 0.75rem;
|
||||
color: white;
|
||||
background-color: rgb(255 255 255 / 0.1);
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
background-color: rgb(255 255 255 / 0.2);
|
||||
transition: background-color 150ms cubic-bezier(0.5, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.cardTitle {
|
||||
font-size: 1.5rem;
|
||||
line-height: 2rem;
|
||||
font-weight: 700;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.cardText {
|
||||
font-size: 1.125rem;
|
||||
line-height: 1.75rem;
|
||||
}
|
||||
|
||||
.showcaseContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.showcaseText {
|
||||
color: white;
|
||||
text-align: center;
|
||||
font-size: 1.5rem;
|
||||
line-height: 2rem;
|
||||
}
|
||||
|
||||
.authContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.loginButton {
|
||||
border-radius: 9999px;
|
||||
background-color: rgb(255 255 255 / 0.1);
|
||||
padding: 0.75rem 2.5rem;
|
||||
font-weight: 600;
|
||||
color: white;
|
||||
text-decoration-line: none;
|
||||
transition: background-color 150ms cubic-bezier(0.5, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.loginButton:hover {
|
||||
background-color: rgb(255 255 255 / 0.2);
|
||||
}
|
||||
@@ -27,8 +27,8 @@ export default function Home() {
|
||||
>
|
||||
<h3 className={styles.cardTitle}>First Steps →</h3>
|
||||
<div className={styles.cardText}>
|
||||
Just the basics - Everything you need to know to set up your
|
||||
database and authentication.
|
||||
Just the basics - Everything you need to know to set up your database and
|
||||
authentication.
|
||||
</div>
|
||||
</Link>
|
||||
<Link
|
||||
@@ -38,8 +38,7 @@ export default function Home() {
|
||||
>
|
||||
<h3 className={styles.cardTitle}>Documentation →</h3>
|
||||
<div className={styles.cardText}>
|
||||
Learn more about Create T3 App, the libraries it uses, and how
|
||||
to deploy it.
|
||||
Learn more about Create T3 App, the libraries it uses, and how to deploy it.
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
@@ -60,7 +59,7 @@ function AuthShowcase() {
|
||||
|
||||
const { data: secretMessage } = api.example.getSecretMessage.useQuery(
|
||||
undefined, // no input
|
||||
{ enabled: sessionData?.user !== undefined },
|
||||
{ enabled: sessionData?.user !== undefined }
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { exampleRouter } from "~/server/api/routers/example";
|
||||
import { promptVariantsRouter } from "~/server/api/routers/promptVariants.router";
|
||||
import { createTRPCRouter } from "~/server/api/trpc";
|
||||
|
||||
/**
|
||||
@@ -7,7 +7,7 @@ import { createTRPCRouter } from "~/server/api/trpc";
|
||||
* All routers added in /api/routers should be manually added here.
|
||||
*/
|
||||
export const appRouter = createTRPCRouter({
|
||||
example: exampleRouter,
|
||||
promptVariants: promptVariantsRouter,
|
||||
});
|
||||
|
||||
// export type definition of API
|
||||
@@ -1,24 +0,0 @@
|
||||
import { z } from "zod";
|
||||
import {
|
||||
createTRPCRouter,
|
||||
publicProcedure,
|
||||
protectedProcedure,
|
||||
} from "~/server/api/trpc";
|
||||
|
||||
export const exampleRouter = createTRPCRouter({
|
||||
hello: publicProcedure
|
||||
.input(z.object({ text: z.string() }))
|
||||
.query(({ input }) => {
|
||||
return {
|
||||
greeting: `Hello ${input.text}`,
|
||||
};
|
||||
}),
|
||||
|
||||
getAll: publicProcedure.query(({ ctx }) => {
|
||||
return ctx.prisma.example.findMany();
|
||||
}),
|
||||
|
||||
getSecretMessage: protectedProcedure.query(() => {
|
||||
return "you can now see this secret message!";
|
||||
}),
|
||||
});
|
||||
17
src/server/api/routers/promptVariants.router.ts
Normal file
17
src/server/api/routers/promptVariants.router.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { z } from "zod";
|
||||
import { createTRPCRouter, publicProcedure, protectedProcedure } from "~/server/api/trpc";
|
||||
import { prisma } from "~/server/db";
|
||||
|
||||
export const promptVariantsRouter = createTRPCRouter({
|
||||
getAll: publicProcedure.input(z.object({ experimentId: z.string() })).query(async ({ input }) => {
|
||||
return await prisma.promptVariant.findMany({
|
||||
where: {
|
||||
experimentId: input.experimentId,
|
||||
},
|
||||
});
|
||||
}),
|
||||
|
||||
getSecretMessage: protectedProcedure.query(() => {
|
||||
return "you can now see this secret message!";
|
||||
}),
|
||||
});
|
||||
@@ -1,16 +0,0 @@
|
||||
html,
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
|
||||
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
@@ -8,7 +8,7 @@ import { httpBatchLink, loggerLink } from "@trpc/client";
|
||||
import { createTRPCNext } from "@trpc/next";
|
||||
import { type inferRouterInputs, type inferRouterOutputs } from "@trpc/server";
|
||||
import superjson from "superjson";
|
||||
import { type AppRouter } from "~/server/api/root";
|
||||
import { type AppRouter } from "~/server/api/root.router";
|
||||
|
||||
const getBaseUrl = () => {
|
||||
if (typeof window !== "undefined") return ""; // browser should use relative url
|
||||
|
||||
Reference in New Issue
Block a user