commit
						83bef7d95e
					
				
					 21 changed files with 249 additions and 79 deletions
				
			
		
							
								
								
									
										83
									
								
								components/team/screens/Team.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								components/team/screens/Team.tsx
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,83 @@ | ||||||
|  | import React from "react"; | ||||||
|  | import Text from "@components/ui/Text"; | ||||||
|  | import Link from "next/link"; | ||||||
|  | import Avatar from "@components/Avatar"; | ||||||
|  | import { ArrowRightIcon } from "@heroicons/react/outline"; | ||||||
|  | import useTheme from "@components/Theme"; | ||||||
|  | import classnames from "classnames"; | ||||||
|  | 
 | ||||||
|  | const Team = ({ team }) => { | ||||||
|  |   useTheme(); | ||||||
|  | 
 | ||||||
|  |   const Member = ({ member }) => { | ||||||
|  |     const classes = classnames( | ||||||
|  |       "group", | ||||||
|  |       "relative", | ||||||
|  |       "flex flex-col", | ||||||
|  |       "space-y-4", | ||||||
|  |       "p-4", | ||||||
|  |       "bg-white dark:bg-opacity-8", | ||||||
|  |       "border border-neutral-200", | ||||||
|  |       "hover:cursor-pointer", | ||||||
|  |       "hover:border-black hover:border-2 dark:border-neutral-700 dark:hover:border-neutral-600", | ||||||
|  |       "rounded-sm", | ||||||
|  |       "hover:shadow-md" | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|  |     return ( | ||||||
|  |       <Link key={member.id} href={`/${member.user.username}`}> | ||||||
|  |         <div className={classes}> | ||||||
|  |           <ArrowRightIcon | ||||||
|  |             className={classnames( | ||||||
|  |               "text-black dark:text-white", | ||||||
|  |               "absolute top-4 right-4", | ||||||
|  |               "h-4 w-4", | ||||||
|  |               "transition-opacity", | ||||||
|  |               "opacity-0 group-hover:opacity-100 group-hover:block" | ||||||
|  |             )} | ||||||
|  |           /> | ||||||
|  | 
 | ||||||
|  |           <Avatar user={member.user} className="w-12 h-12 rounded-full" /> | ||||||
|  | 
 | ||||||
|  |           <section className="space-y-2"> | ||||||
|  |             <Text variant="title">{member.user.name}</Text> | ||||||
|  |             <Text variant="subtitle" className="w-6/8"> | ||||||
|  |               {member.user.bio} | ||||||
|  |             </Text> | ||||||
|  |           </section> | ||||||
|  |         </div> | ||||||
|  |       </Link> | ||||||
|  |     ); | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   const Members = ({ members }) => { | ||||||
|  |     if (!members || members.length === 0) { | ||||||
|  |       return null; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return ( | ||||||
|  |       <section className="mx-auto min-w-full lg:min-w-lg max-w-5xl grid grid-cols-1 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-x-12 gap-y-6"> | ||||||
|  |         {members.map((member) => { | ||||||
|  |           return <Member key={member.id} member={member} />; | ||||||
|  |         })} | ||||||
|  |       </section> | ||||||
|  |     ); | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   return ( | ||||||
|  |     <article className="flex flex-col space-y-8 lg:space-y-12"> | ||||||
|  |       <div className="mb-8 text-center"> | ||||||
|  |         <Avatar | ||||||
|  |           user={{ | ||||||
|  |             email: team.name, | ||||||
|  |           }} | ||||||
|  |           className="mx-auto w-20 h-20 rounded-full mb-4" | ||||||
|  |         /> | ||||||
|  |         <Text variant="headline">{team.name}</Text> | ||||||
|  |       </div> | ||||||
|  |       <Members members={team.members} /> | ||||||
|  |     </article> | ||||||
|  |   ); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | export default Team; | ||||||
|  | @ -1,10 +1,9 @@ | ||||||
| import React from "react"; | import React from "react"; | ||||||
| import classnames from "classnames"; | import classnames from "classnames"; | ||||||
| import { TextProps } from "../Text"; | import { TextProps } from "../Text"; | ||||||
| import Styles from "../Text.module.css"; |  | ||||||
| 
 | 
 | ||||||
| const Body: React.FunctionComponent<TextProps> = (props: TextProps) => { | const Body: React.FunctionComponent<TextProps> = (props: TextProps) => { | ||||||
|   const classes = classnames(Styles["text--body"], props?.className, props?.color); |   const classes = classnames("text-lg leading-relaxed text-gray-900 dark:text-white"); | ||||||
| 
 | 
 | ||||||
|   return <p className={classes}>{props.children}</p>; |   return <p className={classes}>{props.children}</p>; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -1,10 +1,9 @@ | ||||||
| import React from "react"; | import React from "react"; | ||||||
| import classnames from "classnames"; | import classnames from "classnames"; | ||||||
| import { TextProps } from "../Text"; | import { TextProps } from "../Text"; | ||||||
| import Styles from "../Text.module.css"; |  | ||||||
| 
 | 
 | ||||||
| const Caption: React.FunctionComponent<TextProps> = (props: TextProps) => { | const Caption: React.FunctionComponent<TextProps> = (props: TextProps) => { | ||||||
|   const classes = classnames(Styles["text--caption"], props?.className, props?.color); |   const classes = classnames("text-sm text-gray-500 dark:text-white leading-tight"); | ||||||
| 
 | 
 | ||||||
|   return <p className={classes}>{props.children}</p>; |   return <p className={classes}>{props.children}</p>; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -1,10 +1,9 @@ | ||||||
| import React from "react"; | import React from "react"; | ||||||
| import classnames from "classnames"; | import classnames from "classnames"; | ||||||
| import { TextProps } from "../Text"; | import { TextProps } from "../Text"; | ||||||
| import Styles from "../Text.module.css"; |  | ||||||
| 
 | 
 | ||||||
| const Caption2: React.FunctionComponent<TextProps> = (props: TextProps) => { | const Caption2: React.FunctionComponent<TextProps> = (props: TextProps) => { | ||||||
|   const classes = classnames(Styles["text--caption2"], props?.className, props?.color); |   const classes = classnames("text-xs italic text-gray-500 dark:text-white leading-tight"); | ||||||
| 
 | 
 | ||||||
|   return <p className={classes}>{props.children}</p>; |   return <p className={classes}>{props.children}</p>; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -3,7 +3,7 @@ import classnames from "classnames"; | ||||||
| import { TextProps } from "../Text"; | import { TextProps } from "../Text"; | ||||||
| 
 | 
 | ||||||
| const Footnote: React.FunctionComponent<TextProps> = (props: TextProps) => { | const Footnote: React.FunctionComponent<TextProps> = (props: TextProps) => { | ||||||
|   const classes = classnames("text--footnote", props?.className, props?.color); |   const classes = classnames("text-base font-normal text-gray-900 dark:text-white"); | ||||||
| 
 | 
 | ||||||
|   return <p className={classes}>{props.children}</p>; |   return <p className={classes}>{props.children}</p>; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -1,10 +1,9 @@ | ||||||
| import React from "react"; | import React from "react"; | ||||||
| import classnames from "classnames"; | import classnames from "classnames"; | ||||||
| import { TextProps } from "../Text"; | import { TextProps } from "../Text"; | ||||||
| import Styles from "../Text.module.css"; |  | ||||||
| 
 | 
 | ||||||
| const Headline: React.FunctionComponent<TextProps> = (props: TextProps) => { | const Headline: React.FunctionComponent<TextProps> = (props: TextProps) => { | ||||||
|   const classes = classnames(Styles["text--headline"], props?.className, props?.color); |   const classes = classnames("text-xl font-bold text-gray-900 dark:text-white"); | ||||||
| 
 | 
 | ||||||
|   return <h1 className={classes}>{props.children}</h1>; |   return <h1 className={classes}>{props.children}</h1>; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -1,10 +1,9 @@ | ||||||
| import React from "react"; | import React from "react"; | ||||||
| import classnames from "classnames"; | import classnames from "classnames"; | ||||||
| import { TextProps } from "../Text"; | import { TextProps } from "../Text"; | ||||||
| import Styles from "../Text.module.css"; |  | ||||||
| 
 | 
 | ||||||
| const Largetitle: React.FunctionComponent<TextProps> = (props: TextProps) => { | const Largetitle: React.FunctionComponent<TextProps> = (props: TextProps) => { | ||||||
|   const classes = classnames(Styles["text--largetitle"], props?.className, props?.color); |   const classes = classnames("text-2xl font-normal text-gray-900 dark:text-white"); | ||||||
| 
 | 
 | ||||||
|   return <p className={classes}>{props.children}</p>; |   return <p className={classes}>{props.children}</p>; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -1,10 +1,11 @@ | ||||||
| import React from "react"; | import React from "react"; | ||||||
| import classnames from "classnames"; | import classnames from "classnames"; | ||||||
| import { TextProps } from "../Text"; | import { TextProps } from "../Text"; | ||||||
| import Styles from "../Text.module.css"; |  | ||||||
| 
 | 
 | ||||||
| const Overline: React.FunctionComponent<TextProps> = (props: TextProps) => { | const Overline: React.FunctionComponent<TextProps> = (props: TextProps) => { | ||||||
|   const classes = classnames(Styles["text--overline"], props?.className, props?.color); |   const classes = classnames( | ||||||
|  |     "text-sm uppercase font-semibold leading-snug tracking-wide text-gray-900 dark:text-white" | ||||||
|  |   ); | ||||||
| 
 | 
 | ||||||
|   return <p className={classes}>{props.children}</p>; |   return <p className={classes}>{props.children}</p>; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -1,10 +1,9 @@ | ||||||
| import React from "react"; | import React from "react"; | ||||||
| import classnames from "classnames"; | import classnames from "classnames"; | ||||||
| import { TextProps } from "../Text"; | import { TextProps } from "../Text"; | ||||||
| import Styles from "../Text.module.css"; |  | ||||||
| 
 | 
 | ||||||
| const Subheadline: React.FunctionComponent<TextProps> = (props: TextProps) => { | const Subheadline: React.FunctionComponent<TextProps> = (props: TextProps) => { | ||||||
|   const classes = classnames(Styles["text--subheadline"], props?.className, props?.color); |   const classes = classnames("text-xl text-gray-500 dark:text-white leading-relaxed"); | ||||||
| 
 | 
 | ||||||
|   return <p className={classes}>{props.children}</p>; |   return <p className={classes}>{props.children}</p>; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -1,10 +1,9 @@ | ||||||
| import React from "react"; | import React from "react"; | ||||||
| import classnames from "classnames"; | import classnames from "classnames"; | ||||||
| import { TextProps } from "../Text"; | import { TextProps } from "../Text"; | ||||||
| import Styles from "../Text.module.css"; |  | ||||||
| 
 | 
 | ||||||
| const Subtitle: React.FunctionComponent<TextProps> = (props: TextProps) => { | const Subtitle: React.FunctionComponent<TextProps> = (props: TextProps) => { | ||||||
|   const classes = classnames(Styles["text--subtitle"], props?.className, props?.color); |   const classes = classnames("ext-sm text-neutral-500 dark:text-white"); | ||||||
| 
 | 
 | ||||||
|   return <p className={classes}>{props.children}</p>; |   return <p className={classes}>{props.children}</p>; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -1,52 +0,0 @@ | ||||||
| /* strong { |  | ||||||
|   @apply font-medium; |  | ||||||
| } */ |  | ||||||
| 
 |  | ||||||
| .text--body { |  | ||||||
|   @apply text-lg leading-relaxed; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .text--overline { |  | ||||||
|   @apply text-sm uppercase font-semibold leading-snug tracking-wide; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .text--caption { |  | ||||||
|   @apply text-sm text-gray-500 leading-tight; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .text--caption2 { |  | ||||||
|   @apply text-xs italic text-gray-500 leading-tight; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .text--footnote { |  | ||||||
|   @apply text-base  font-normal; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .text--headline { |  | ||||||
|   /* @apply text-base  font-normal; */ |  | ||||||
|   @apply text-3xl leading-8 font-semibold tracking-tight text-gray-900 sm:text-4xl; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .text--subheadline { |  | ||||||
|   @apply text-xl text-gray-500 leading-relaxed; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .text--largetitle { |  | ||||||
|   @apply text-2xl  font-normal; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .text--subtitle { |  | ||||||
|   @apply text-base  font-normal; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .text--title { |  | ||||||
|   @apply text-base  font-normal; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .text--title2 { |  | ||||||
|   @apply text-base  font-normal; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .text--title3 { |  | ||||||
|   @apply text-xs font-semibold leading-tight; |  | ||||||
| } |  | ||||||
|  | @ -1,10 +1,9 @@ | ||||||
| import React from "react"; | import React from "react"; | ||||||
| import classnames from "classnames"; | import classnames from "classnames"; | ||||||
| import { TextProps } from "../Text"; | import { TextProps } from "../Text"; | ||||||
| import Styles from "../Text.module.css"; |  | ||||||
| 
 | 
 | ||||||
| const Title: React.FunctionComponent<TextProps> = (props: TextProps) => { | const Title: React.FunctionComponent<TextProps> = (props: TextProps) => { | ||||||
|   const classes = classnames(Styles["text--title"], props?.className, props?.color); |   const classes = classnames("font-medium text-neutral-900 dark:text-white"); | ||||||
| 
 | 
 | ||||||
|   return <p className={classes}>{props.children}</p>; |   return <p className={classes}>{props.children}</p>; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -1,10 +1,9 @@ | ||||||
| import React from "react"; | import React from "react"; | ||||||
| import classnames from "classnames"; | import classnames from "classnames"; | ||||||
| import { TextProps } from "../Text"; | import { TextProps } from "../Text"; | ||||||
| import Styles from "../Text.module.css"; |  | ||||||
| 
 | 
 | ||||||
| const Title2: React.FunctionComponent<TextProps> = (props: TextProps) => { | const Title2: React.FunctionComponent<TextProps> = (props: TextProps) => { | ||||||
|   const classes = classnames(Styles["text--title2"], props?.className, props?.color); |   const classes = classnames("text-base font-normal text-gray-900 dark:text-white"); | ||||||
| 
 | 
 | ||||||
|   return <p className={classes}>{props.children}</p>; |   return <p className={classes}>{props.children}</p>; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -1,10 +1,9 @@ | ||||||
| import React from "react"; | import React from "react"; | ||||||
| import classnames from "classnames"; | import classnames from "classnames"; | ||||||
| import { TextProps } from "../Text"; | import { TextProps } from "../Text"; | ||||||
| import Styles from "../Text.module.css"; |  | ||||||
| 
 | 
 | ||||||
| const Title3: React.FunctionComponent<TextProps> = (props: TextProps) => { | const Title3: React.FunctionComponent<TextProps> = (props: TextProps) => { | ||||||
|   const classes = classnames(Styles["text--title3"], props?.className, props?.color); |   const classes = classnames("text-xs font-semibold leading-tight text-gray-900 dark:text-white"); | ||||||
| 
 | 
 | ||||||
|   return <p className={classes}>{props.children}</p>; |   return <p className={classes}>{props.children}</p>; | ||||||
| }; | }; | ||||||
|  |  | ||||||
							
								
								
									
										5
									
								
								lib/slugify.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								lib/slugify.ts
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,5 @@ | ||||||
|  | export const slugify = (str: string) => { | ||||||
|  |   return str.replace(/\s+/g, "-").toLowerCase(); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | export default slugify; | ||||||
							
								
								
									
										54
									
								
								lib/teams/getTeam.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								lib/teams/getTeam.ts
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,54 @@ | ||||||
|  | import { Team } from "@prisma/client"; | ||||||
|  | import prisma from "@lib/prisma"; | ||||||
|  | import logger from "@lib/logger"; | ||||||
|  | 
 | ||||||
|  | const log = logger.getChildLogger({ prefix: ["[lib] getTeam"] }); | ||||||
|  | export const getTeam = async (idOrSlug: string): Promise<Team | null> => { | ||||||
|  |   const teamIdOrSlug = idOrSlug; | ||||||
|  | 
 | ||||||
|  |   let team = null; | ||||||
|  | 
 | ||||||
|  |   log.debug(`{teamIdOrSlug} ${teamIdOrSlug}`); | ||||||
|  | 
 | ||||||
|  |   const teamSelectInput = { | ||||||
|  |     id: true, | ||||||
|  |     name: true, | ||||||
|  |     slug: true, | ||||||
|  |     members: { | ||||||
|  |       where: { | ||||||
|  |         accepted: true, | ||||||
|  |       }, | ||||||
|  |       select: { | ||||||
|  |         user: { | ||||||
|  |           select: { | ||||||
|  |             id: true, | ||||||
|  |             username: true, | ||||||
|  |             email: true, | ||||||
|  |             name: true, | ||||||
|  |             bio: true, | ||||||
|  |             avatar: true, | ||||||
|  |             theme: true, | ||||||
|  |           }, | ||||||
|  |         }, | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   team = await prisma.team.findFirst({ | ||||||
|  |     where: { | ||||||
|  |       OR: [ | ||||||
|  |         { | ||||||
|  |           id: parseInt(teamIdOrSlug) || undefined, | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |           slug: teamIdOrSlug, | ||||||
|  |         }, | ||||||
|  |       ], | ||||||
|  |     }, | ||||||
|  |     select: teamSelectInput, | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   log.debug(`{team}`, { team }); | ||||||
|  | 
 | ||||||
|  |   return team; | ||||||
|  | }; | ||||||
|  | @ -1,6 +1,7 @@ | ||||||
| import type { NextApiRequest, NextApiResponse } from "next"; | import type { NextApiRequest, NextApiResponse } from "next"; | ||||||
| import prisma from "../../lib/prisma"; | import prisma from "../../lib/prisma"; | ||||||
| import { getSession } from "next-auth/client"; | import { getSession } from "next-auth/client"; | ||||||
|  | import slugify from "@lib/slugify"; | ||||||
| 
 | 
 | ||||||
| export default async function handler(req: NextApiRequest, res: NextApiResponse) { | export default async function handler(req: NextApiRequest, res: NextApiResponse) { | ||||||
|   const session = await getSession({ req: req }); |   const session = await getSession({ req: req }); | ||||||
|  | @ -11,11 +12,22 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   if (req.method === "POST") { |   if (req.method === "POST") { | ||||||
|     // TODO: Prevent creating a team with identical names?
 |     const slug = slugify(req.body.name); | ||||||
|  | 
 | ||||||
|  |     const nameCollisions = await prisma.team.count({ | ||||||
|  |       where: { | ||||||
|  |         OR: [{ name: req.body.name }, { slug: slug }], | ||||||
|  |       }, | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     if (nameCollisions > 0) { | ||||||
|  |       return res.status(409).json({ errorCode: "TeamNameCollision", message: "Team name already take." }); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     const createTeam = await prisma.team.create({ |     const createTeam = await prisma.team.create({ | ||||||
|       data: { |       data: { | ||||||
|         name: req.body.name, |         name: req.body.name, | ||||||
|  |         slug: slug, | ||||||
|       }, |       }, | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										54
									
								
								pages/team/[idOrSlug].tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								pages/team/[idOrSlug].tsx
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,54 @@ | ||||||
|  | import { GetServerSideProps } from "next"; | ||||||
|  | import Head from "next/head"; | ||||||
|  | 
 | ||||||
|  | import Theme from "@components/Theme"; | ||||||
|  | import { getTeam } from "@lib/teams/getTeam"; | ||||||
|  | import Team from "@components/team/screens/Team"; | ||||||
|  | 
 | ||||||
|  | export default function Page(props) { | ||||||
|  |   const { isReady } = Theme(); | ||||||
|  | 
 | ||||||
|  |   return ( | ||||||
|  |     isReady && ( | ||||||
|  |       <div> | ||||||
|  |         <Head> | ||||||
|  |           <title>{props.team.name} | Calendso</title> | ||||||
|  |           <link rel="icon" href="/favicon.ico" /> | ||||||
|  |         </Head> | ||||||
|  | 
 | ||||||
|  |         <main className="mx-auto py-24 px-4"> | ||||||
|  |           <Team team={props.team} /> | ||||||
|  |         </main> | ||||||
|  |       </div> | ||||||
|  |     ) | ||||||
|  |   ); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export const getServerSideProps: GetServerSideProps = async (context) => { | ||||||
|  |   const teamIdOrSlug = Array.isArray(context.query?.idOrSlug) | ||||||
|  |     ? context.query.idOrSlug.pop() | ||||||
|  |     : context.query.idOrSlug; | ||||||
|  | 
 | ||||||
|  |   const team = await getTeam(teamIdOrSlug); | ||||||
|  | 
 | ||||||
|  |   if (!team) { | ||||||
|  |     return { | ||||||
|  |       notFound: true, | ||||||
|  |     }; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   return { | ||||||
|  |     props: { | ||||||
|  |       team, | ||||||
|  |     }, | ||||||
|  |   }; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | // Auxiliary methods
 | ||||||
|  | export function getRandomColorCode(): string { | ||||||
|  |   let color = "#"; | ||||||
|  |   for (let idx = 0; idx < 6; idx++) { | ||||||
|  |     color += Math.floor(Math.random() * 10); | ||||||
|  |   } | ||||||
|  |   return color; | ||||||
|  | } | ||||||
|  | @ -0,0 +1,2 @@ | ||||||
|  | -- AlterTable | ||||||
|  | ALTER TABLE "Team" ADD COLUMN     "slug" TEXT; | ||||||
|  | @ -72,6 +72,7 @@ model User { | ||||||
| model Team { | model Team { | ||||||
|   id            Int       @default(autoincrement()) @id |   id            Int       @default(autoincrement()) @id | ||||||
|   name          String? |   name          String? | ||||||
|  |   slug          String? | ||||||
|   members       Membership[] |   members       Membership[] | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -95,22 +95,28 @@ module.exports = { | ||||||
|         inter: ["Inter", "sans-serif"], |         inter: ["Inter", "sans-serif"], | ||||||
|         kollektif: ["Kollektif", "sans-serif"], |         kollektif: ["Kollektif", "sans-serif"], | ||||||
|       }, |       }, | ||||||
|       maxHeight: (theme) => ({ |       maxHeight: (theme, { breakpoints }) => ({ | ||||||
|         0: "0", |         0: "0", | ||||||
|         97: "25rem", |         97: "25rem", | ||||||
|         ...theme("spacing"), |         ...theme("spacing"), | ||||||
|  |         ...breakpoints(theme("screens")), | ||||||
|  |         ...theme("screens"), | ||||||
|         full: "100%", |         full: "100%", | ||||||
|         screen: "100vh", |         screen: "100vh", | ||||||
|       }), |       }), | ||||||
|       minHeight: (theme) => ({ |       minHeight: (theme, { breakpoints }) => ({ | ||||||
|         0: "0", |         0: "0", | ||||||
|         ...theme("spacing"), |         ...theme("spacing"), | ||||||
|  |         ...breakpoints(theme("screens")), | ||||||
|  |         ...theme("screens"), | ||||||
|         full: "100%", |         full: "100%", | ||||||
|         screen: "100vh", |         screen: "100vh", | ||||||
|       }), |       }), | ||||||
|       minWidth: (theme) => ({ |       minWidth: (theme, { breakpoints }) => ({ | ||||||
|         0: "0", |         0: "0", | ||||||
|         ...theme("spacing"), |         ...theme("spacing"), | ||||||
|  |         ...breakpoints(theme("screens")), | ||||||
|  |         ...theme("screens"), | ||||||
|         full: "100%", |         full: "100%", | ||||||
|         screen: "100vw", |         screen: "100vw", | ||||||
|       }), |       }), | ||||||
|  | @ -118,9 +124,23 @@ module.exports = { | ||||||
|         0: "0", |         0: "0", | ||||||
|         ...theme("spacing"), |         ...theme("spacing"), | ||||||
|         ...breakpoints(theme("screens")), |         ...breakpoints(theme("screens")), | ||||||
|  |         ...theme("screens"), | ||||||
|         full: "100%", |         full: "100%", | ||||||
|         screen: "100vw", |         screen: "100vw", | ||||||
|       }), |       }), | ||||||
|  |       opacity: { | ||||||
|  |         0: "0", | ||||||
|  |         8: "0.08", | ||||||
|  |         10: "0.10", | ||||||
|  |         20: "0.20", | ||||||
|  |         40: "0.40", | ||||||
|  |         60: "0.60", | ||||||
|  |         80: "0.80", | ||||||
|  |         25: "0.25", | ||||||
|  |         50: "0.5", | ||||||
|  |         75: "0.75", | ||||||
|  |         100: "1", | ||||||
|  |       }, | ||||||
|     }, |     }, | ||||||
|   }, |   }, | ||||||
|   variants: { |   variants: { | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Peer_Rich
						Peer_Rich