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