misc: updates & shit
This commit is contained in:
parent
e22c7dafa1
commit
ad66016115
20 changed files with 2087 additions and 1303 deletions
|
@ -1,4 +1,4 @@
|
|||
import UserAuthForm from '@/ui/UserAuthForm';
|
||||
import UserAuthForm from '@/components/ui/UserAuthForm';
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import UserAuthForm from '@/ui/UserAuthForm';
|
||||
import UserAuthForm from '@/components/ui/UserAuthForm';
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
|
|
|
@ -4,7 +4,7 @@ import { useContext } from 'react';
|
|||
|
||||
import { UserContext } from '@/context/user';
|
||||
|
||||
import Badge from '@/ui/Badge';
|
||||
import Badge from '@/components/ui/Badge';
|
||||
|
||||
export default function Page() {
|
||||
const { data: me } = useContext(UserContext);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { type ReactNode } from 'react';
|
||||
|
||||
import { UserProvider } from '@/context/user';
|
||||
import Wrapper from '@/ui/dashboard/Wrapper';
|
||||
import Wrapper from '@/components/ui/dashboard/Wrapper';
|
||||
import { cookies } from 'next/headers';
|
||||
|
||||
export default async function Layout({ children }: { children: ReactNode }) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import Leaderboard from '@/ui/Leaderboard';
|
||||
import Leaderboard from '@/components/ui/Leaderboard';
|
||||
import { cookies } from 'next/headers';
|
||||
|
||||
export const metadata = {
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
import { useContext } from 'react';
|
||||
|
||||
import Card from '@/components/ui/Card';
|
||||
import { UserContext } from '@/context/user';
|
||||
import Card from '@/ui/Card';
|
||||
|
||||
export default function Page() {
|
||||
const { data: me, isLoading } = useContext(UserContext);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { getPuzzle } from '@/lib/puzzles';
|
||||
import Puzzle from '@/ui/Puzzle';
|
||||
import SWRFallback from '@/ui/SWRFallback';
|
||||
import Puzzle from '@/components/ui/Puzzle';
|
||||
import SWRFallback from '@/components/ui/SWRFallback';
|
||||
import type { Metadata } from 'next';
|
||||
import { cookies } from 'next/headers';
|
||||
import { notFound } from 'next/navigation';
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { cookies } from 'next/headers';
|
||||
|
||||
import Puzzles from '@/ui/Puzzles';
|
||||
import SWRFallback from '@/ui/SWRFallback';
|
||||
import Puzzles from '@/components/ui/Puzzles';
|
||||
import SWRFallback from '@/components/ui/SWRFallback';
|
||||
import { getPuzzles } from '@/lib/puzzles';
|
||||
import { notFound } from 'next/navigation';
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import '@/styles/globals.css';
|
||||
import 'remixicon/fonts/remixicon.css';
|
||||
import '@/styles/global.css';
|
||||
|
||||
import { type Metadata } from 'next';
|
||||
import { Fira_Code } from 'next/font/google';
|
||||
|
@ -8,10 +7,13 @@ import { type ReactNode } from 'react';
|
|||
|
||||
import { cn, getURL } from '@/lib/utils';
|
||||
|
||||
import { ThemeProvider } from '@/components/ThemeProvider';
|
||||
|
||||
const sans = localFont({
|
||||
variable: '--font-sans',
|
||||
src: './fonts/Karrik.woff2',
|
||||
weight: 'variable'
|
||||
weight: 'variable',
|
||||
display: 'swap'
|
||||
});
|
||||
|
||||
const code = Fira_Code({
|
||||
|
@ -28,26 +30,6 @@ export const metadata: Metadata = {
|
|||
},
|
||||
description: "Apprendre la programmation et la cybersécurité en s'amusant.",
|
||||
// manifest: getURL('/favicon/site.webmanifest'),
|
||||
openGraph: {
|
||||
title: {
|
||||
default: 'Peer-at Code',
|
||||
template: `%s - Peer-at Code`
|
||||
},
|
||||
description: "Apprendre la programmation et la cybersécurité en s'amusant.",
|
||||
url: getURL(),
|
||||
siteName: 'Peer-at Code',
|
||||
// images: getURL('/assets/social.jpg'),
|
||||
type: 'website'
|
||||
},
|
||||
twitter: {
|
||||
card: 'summary_large_image',
|
||||
title: {
|
||||
default: 'Peer-at Code',
|
||||
template: `%s - Peer-at Code`
|
||||
},
|
||||
description: "Apprendre la programmation et la cybersécurité en s'amusant."
|
||||
// images: getURL('/assets/social.jpg'),
|
||||
},
|
||||
alternates: {
|
||||
canonical: getURL()
|
||||
},
|
||||
|
@ -74,14 +56,16 @@ export default function RootLayout({ children }: { children: ReactNode }) {
|
|||
lang="fr"
|
||||
dir="ltr"
|
||||
className={cn(
|
||||
'scroll-smooth bg-gradient-to-b from-primary-800 to-primary-900 [color-scheme:dark]',
|
||||
'scroll-smooth bg-gradient-to-b from-primary-800 to-primary-900',
|
||||
sans.variable,
|
||||
code.variable
|
||||
)}
|
||||
>
|
||||
<head />
|
||||
<body className="relative min-h-screen">
|
||||
<main>{children}</main>
|
||||
<ThemeProvider attribute="class" defaultTheme="dark" enableSystem>
|
||||
<main>{children}</main>
|
||||
</ThemeProvider>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import AppLink from '@/ui/AppLink';
|
||||
import Console from '@/ui/Console';
|
||||
import AppLink from '@/components/ui/AppLink';
|
||||
import Console from '@/components/ui/Console';
|
||||
import Image from 'next/image';
|
||||
|
||||
export default function Page() {
|
||||
|
|
15
components.json
Normal file
15
components.json
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"$schema": "https://ui.shadcn.com/schema.json",
|
||||
"style": "default",
|
||||
"rsc": true,
|
||||
"tailwind": {
|
||||
"config": "tailwind.config.js",
|
||||
"css": "styles/global.css",
|
||||
"baseColor": "slate",
|
||||
"cssVariables": true
|
||||
},
|
||||
"aliases": {
|
||||
"components": "@/components",
|
||||
"utils": "@/lib/utils"
|
||||
}
|
||||
}
|
187
lib/hooks/use-toast.ts
Normal file
187
lib/hooks/use-toast.ts
Normal file
|
@ -0,0 +1,187 @@
|
|||
// Inspired by react-hot-toast library
|
||||
import * as React from 'react';
|
||||
|
||||
import type { ToastActionElement, ToastProps } from '@/components/ui/Toast';
|
||||
|
||||
const TOAST_LIMIT = 1;
|
||||
const TOAST_REMOVE_DELAY = 1000000;
|
||||
|
||||
type ToasterToast = ToastProps & {
|
||||
id: string;
|
||||
title?: React.ReactNode;
|
||||
description?: React.ReactNode;
|
||||
action?: ToastActionElement;
|
||||
};
|
||||
|
||||
const actionTypes = {
|
||||
ADD_TOAST: 'ADD_TOAST',
|
||||
UPDATE_TOAST: 'UPDATE_TOAST',
|
||||
DISMISS_TOAST: 'DISMISS_TOAST',
|
||||
REMOVE_TOAST: 'REMOVE_TOAST'
|
||||
} as const;
|
||||
|
||||
let count = 0;
|
||||
|
||||
function genId() {
|
||||
count = (count + 1) % Number.MAX_VALUE;
|
||||
return count.toString();
|
||||
}
|
||||
|
||||
type ActionType = typeof actionTypes;
|
||||
|
||||
type Action =
|
||||
| {
|
||||
type: ActionType['ADD_TOAST'];
|
||||
toast: ToasterToast;
|
||||
}
|
||||
| {
|
||||
type: ActionType['UPDATE_TOAST'];
|
||||
toast: Partial<ToasterToast>;
|
||||
}
|
||||
| {
|
||||
type: ActionType['DISMISS_TOAST'];
|
||||
toastId?: ToasterToast['id'];
|
||||
}
|
||||
| {
|
||||
type: ActionType['REMOVE_TOAST'];
|
||||
toastId?: ToasterToast['id'];
|
||||
};
|
||||
|
||||
interface State {
|
||||
toasts: ToasterToast[];
|
||||
}
|
||||
|
||||
const toastTimeouts = new Map<string, ReturnType<typeof setTimeout>>();
|
||||
|
||||
const addToRemoveQueue = (toastId: string) => {
|
||||
if (toastTimeouts.has(toastId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const timeout = setTimeout(() => {
|
||||
toastTimeouts.delete(toastId);
|
||||
dispatch({
|
||||
type: 'REMOVE_TOAST',
|
||||
toastId: toastId
|
||||
});
|
||||
}, TOAST_REMOVE_DELAY);
|
||||
|
||||
toastTimeouts.set(toastId, timeout);
|
||||
};
|
||||
|
||||
export const reducer = (state: State, action: Action): State => {
|
||||
switch (action.type) {
|
||||
case 'ADD_TOAST':
|
||||
return {
|
||||
...state,
|
||||
toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT)
|
||||
};
|
||||
|
||||
case 'UPDATE_TOAST':
|
||||
return {
|
||||
...state,
|
||||
toasts: state.toasts.map((t) => (t.id === action.toast.id ? { ...t, ...action.toast } : t))
|
||||
};
|
||||
|
||||
case 'DISMISS_TOAST': {
|
||||
const { toastId } = action;
|
||||
|
||||
// ! Side effects ! - This could be extracted into a dismissToast() action,
|
||||
// but I'll keep it here for simplicity
|
||||
if (toastId) {
|
||||
addToRemoveQueue(toastId);
|
||||
} else {
|
||||
state.toasts.forEach((toast) => {
|
||||
addToRemoveQueue(toast.id);
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
toasts: state.toasts.map((t) =>
|
||||
t.id === toastId || toastId === undefined
|
||||
? {
|
||||
...t,
|
||||
open: false
|
||||
}
|
||||
: t
|
||||
)
|
||||
};
|
||||
}
|
||||
case 'REMOVE_TOAST':
|
||||
if (action.toastId === undefined) {
|
||||
return {
|
||||
...state,
|
||||
toasts: []
|
||||
};
|
||||
}
|
||||
return {
|
||||
...state,
|
||||
toasts: state.toasts.filter((t) => t.id !== action.toastId)
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const listeners: Array<(state: State) => void> = [];
|
||||
|
||||
let memoryState: State = { toasts: [] };
|
||||
|
||||
function dispatch(action: Action) {
|
||||
memoryState = reducer(memoryState, action);
|
||||
listeners.forEach((listener) => {
|
||||
listener(memoryState);
|
||||
});
|
||||
}
|
||||
|
||||
type Toast = Omit<ToasterToast, 'id'>;
|
||||
|
||||
function toast({ ...props }: Toast) {
|
||||
const id = genId();
|
||||
|
||||
const update = (props: ToasterToast) =>
|
||||
dispatch({
|
||||
type: 'UPDATE_TOAST',
|
||||
toast: { ...props, id }
|
||||
});
|
||||
const dismiss = () => dispatch({ type: 'DISMISS_TOAST', toastId: id });
|
||||
|
||||
dispatch({
|
||||
type: 'ADD_TOAST',
|
||||
toast: {
|
||||
...props,
|
||||
id,
|
||||
open: true,
|
||||
onOpenChange: (open: any) => {
|
||||
if (!open) dismiss();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
id: id,
|
||||
dismiss,
|
||||
update
|
||||
};
|
||||
}
|
||||
|
||||
function useToast() {
|
||||
const [state, setState] = React.useState<State>(memoryState);
|
||||
|
||||
React.useEffect(() => {
|
||||
listeners.push(setState);
|
||||
return () => {
|
||||
const index = listeners.indexOf(setState);
|
||||
if (index > -1) {
|
||||
listeners.splice(index, 1);
|
||||
}
|
||||
};
|
||||
}, [state]);
|
||||
|
||||
return {
|
||||
...state,
|
||||
toast,
|
||||
dismiss: (toastId?: string) => dispatch({ type: 'DISMISS_TOAST', toastId })
|
||||
};
|
||||
}
|
||||
|
||||
export { useToast, toast };
|
|
@ -1,3 +1,6 @@
|
|||
import { Icons, type Icon } from '@/components/ui/Icon';
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
/**
|
||||
* A navigation item.
|
||||
*
|
||||
|
|
|
@ -29,7 +29,7 @@ export const getPlayer = async ({
|
|||
export type Player = {
|
||||
email: string;
|
||||
pseudo: string;
|
||||
firstnames: string;
|
||||
firstname: string;
|
||||
lastname: string;
|
||||
description: string;
|
||||
avatar: string;
|
||||
|
|
|
@ -2,9 +2,6 @@
|
|||
const nextConfig = {
|
||||
reactStrictMode: true,
|
||||
swcMinify: true,
|
||||
experimental: {
|
||||
scrollRestoration: true
|
||||
},
|
||||
redirects: async () => {
|
||||
return [
|
||||
{
|
||||
|
|
19
package.json
19
package.json
|
@ -20,25 +20,34 @@
|
|||
},
|
||||
"homepage": "https://github.com/Peer-at-Code/peer-at-code#readme",
|
||||
"dependencies": {
|
||||
"@hookform/resolvers": "^3.1.0",
|
||||
"@radix-ui/react-dialog": "^1.0.3",
|
||||
"@radix-ui/react-label": "^2.0.2",
|
||||
"@radix-ui/react-popover": "^1.0.5",
|
||||
"@radix-ui/react-select": "^1.2.2",
|
||||
"@radix-ui/react-slot": "^1.0.2",
|
||||
"@radix-ui/react-toast": "^1.1.4",
|
||||
"boring-avatars": "^1.7.0",
|
||||
"class-variance-authority": "^0.6.0",
|
||||
"clsx": "^1.2.1",
|
||||
"edge-csrf": "^1.0.3",
|
||||
"framer-motion": "^10.12.4",
|
||||
"js-cookie": "^3.0.1",
|
||||
"next": "13.4.0",
|
||||
"lucide-react": "^0.252.0",
|
||||
"next": "13.4.8",
|
||||
"next-themes": "^0.2.1",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-hook-form": "^7.43.1",
|
||||
"react-hook-form": "^7.44.2",
|
||||
"react-markdown": "^8.0.5",
|
||||
"remark-breaks": "^3.0.2",
|
||||
"remark-gfm": "^3.0.1",
|
||||
"remixicon": "^2.5.0",
|
||||
"remixicon": "^3.3.0",
|
||||
"sharp": "^0.32.1",
|
||||
"swr": "^2.0.3",
|
||||
"tailwind-merge": "^1.9.0",
|
||||
"zod": "^3.20.2"
|
||||
"tailwind-merge": "^1.12.0",
|
||||
"tailwindcss-animate": "^1.0.5",
|
||||
"zod": "^3.21.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/forms": "^0.5.3",
|
||||
|
|
2918
pnpm-lock.yaml
generated
2918
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load diff
93
styles/global.css
Normal file
93
styles/global.css
Normal file
|
@ -0,0 +1,93 @@
|
|||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 222.2 84% 4.9%;
|
||||
|
||||
--muted: 210 40% 96.1%;
|
||||
--muted-foreground: 215.4 16.3% 46.9%;
|
||||
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 222.2 84% 4.9%;
|
||||
|
||||
--card: 0 0% 100%;
|
||||
--card-foreground: 222.2 84% 4.9%;
|
||||
|
||||
--border: 214.3 31.8% 91.4%;
|
||||
--input: 214.3 31.8% 91.4%;
|
||||
|
||||
--primary: 222.2 47.4% 11.2%;
|
||||
--primary-foreground: 210 40% 98%;
|
||||
|
||||
--secondary: 210 40% 96.1%;
|
||||
--secondary-foreground: 222.2 47.4% 11.2%;
|
||||
|
||||
--accent: 210 40% 96.1%;
|
||||
--accent-foreground: 222.2 47.4% 11.2%;
|
||||
|
||||
--destructive: 0 84.2% 60.2%;
|
||||
--destructive-foreground: 210 40% 98%;
|
||||
|
||||
--ring: 215 20.2% 65.1%;
|
||||
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: 222.2 84% 4.9%;
|
||||
--foreground: 210 40% 98%;
|
||||
|
||||
--muted: 217.2 32.6% 17.5%;
|
||||
--muted-foreground: 215 20.2% 65.1%;
|
||||
|
||||
--popover: 222.2 84% 4.9%;
|
||||
--popover-foreground: 210 40% 98%;
|
||||
|
||||
--card: 222.2 84% 4.9%;
|
||||
--card-foreground: 210 40% 98%;
|
||||
|
||||
--border: 217.2 32.6% 17.5%;
|
||||
--input: 217.2 32.6% 17.5%;
|
||||
|
||||
--primary: 210 40% 98%;
|
||||
--primary-foreground: 222.2 47.4% 11.2%;
|
||||
|
||||
--secondary: 217.2 32.6% 17.5%;
|
||||
--secondary-foreground: 210 40% 98%;
|
||||
|
||||
--accent: 217.2 32.6% 17.5%;
|
||||
--accent-foreground: 210 40% 98%;
|
||||
|
||||
--destructive: 0 62.8% 30.6%;
|
||||
--destructive-foreground: 0 85.7% 97.3%;
|
||||
|
||||
--ring: 217.2 32.6% 17.5%;
|
||||
}
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border;
|
||||
}
|
||||
body {
|
||||
@apply text-foreground;
|
||||
}
|
||||
}
|
||||
|
||||
@layer components {
|
||||
.console {
|
||||
@apply relative top-0.5 inline-block;
|
||||
}
|
||||
input:-webkit-autofill,
|
||||
input:-webkit-autofill:hover,
|
||||
input:-webkit-autofill:focus,
|
||||
textarea:-webkit-autofill,
|
||||
textarea:-webkit-autofill:hover,
|
||||
textarea:-webkit-autofill:focus {
|
||||
-webkit-box-shadow: 0 0 0px 1000px hsl(258deg 15% 17%) inset;
|
||||
transition: background-color 5000s ease-in-out 0s;
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer components {
|
||||
.console {
|
||||
@apply relative top-0.5 inline-block;
|
||||
}
|
||||
input:-webkit-autofill,
|
||||
input:-webkit-autofill:hover,
|
||||
input:-webkit-autofill:focus,
|
||||
textarea:-webkit-autofill,
|
||||
textarea:-webkit-autofill:hover,
|
||||
textarea:-webkit-autofill:focus {
|
||||
-webkit-box-shadow: 0 0 0px 1000px hsl(258deg 15% 17%) inset;
|
||||
transition: background-color 5000s ease-in-out 0s;
|
||||
}
|
||||
}
|
|
@ -3,19 +3,60 @@ const defaultTheme = require('tailwindcss/defaultTheme');
|
|||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
mode: 'jit',
|
||||
content: ['./app/**/*.{js,ts,jsx,tsx}', './ui/**/*.{js,ts,jsx,tsx}'],
|
||||
future: {
|
||||
hoverOnlyWhenSupported: true
|
||||
},
|
||||
darkMode: ['class'],
|
||||
content: [
|
||||
'./pages/**/*.{ts,tsx}',
|
||||
'./components/**/*.{ts,tsx}',
|
||||
'./app/**/*.{ts,tsx}',
|
||||
'./src/**/*.{ts,tsx}'
|
||||
],
|
||||
theme: {
|
||||
container: {
|
||||
center: true,
|
||||
padding: '2rem',
|
||||
screens: {
|
||||
'2xl': '1400px'
|
||||
}
|
||||
},
|
||||
extend: {
|
||||
fontFamily: {
|
||||
sans: ['var(--font-sans)', ...defaultTheme.fontFamily.sans],
|
||||
code: ['var(--font-code)', ...defaultTheme.fontFamily.serif]
|
||||
},
|
||||
colors: {
|
||||
...require('tailwindcss/colors'),
|
||||
border: 'hsl(var(--border))',
|
||||
input: 'hsl(var(--input))',
|
||||
ring: 'hsl(var(--ring))',
|
||||
background: 'hsl(var(--background))',
|
||||
foreground: 'hsl(var(--foreground))',
|
||||
primary: {
|
||||
DEFAULT: 'hsl(var(--primary))',
|
||||
foreground: 'hsl(var(--primary-foreground))'
|
||||
},
|
||||
secondary: {
|
||||
DEFAULT: 'hsl(var(--secondary))',
|
||||
foreground: 'hsl(var(--secondary-foreground))'
|
||||
},
|
||||
destructive: {
|
||||
DEFAULT: 'hsl(var(--destructive))',
|
||||
foreground: 'hsl(var(--destructive-foreground))'
|
||||
},
|
||||
muted: {
|
||||
DEFAULT: 'hsl(var(--muted))',
|
||||
foreground: 'hsl(var(--muted-foreground))'
|
||||
},
|
||||
accent: {
|
||||
DEFAULT: 'hsl(var(--accent))',
|
||||
foreground: 'hsl(var(--accent-foreground))'
|
||||
},
|
||||
popover: {
|
||||
DEFAULT: 'hsl(var(--popover))',
|
||||
foreground: 'hsl(var(--popover-foreground))'
|
||||
},
|
||||
card: {
|
||||
DEFAULT: 'hsl(var(--card))',
|
||||
foreground: 'hsl(var(--card-foreground))'
|
||||
},
|
||||
primary: {
|
||||
900: 'hsl(258deg 15% 7%)',
|
||||
800: 'hsl(258deg 15% 11%)',
|
||||
|
@ -83,8 +124,27 @@ module.exports = {
|
|||
tertiary: 'hsl(258deg 8% 65%)',
|
||||
secondaryAccent: '#e2e8f0',
|
||||
muted: 'hsl(258deg 7% 46%)'
|
||||
},
|
||||
borderRadius: {
|
||||
lg: 'var(--radius)',
|
||||
md: 'calc(var(--radius) - 2px)',
|
||||
sm: 'calc(var(--radius) - 4px)'
|
||||
},
|
||||
keyframes: {
|
||||
'accordion-down': {
|
||||
from: { height: 0 },
|
||||
to: { height: 'var(--radix-accordion-content-height)' }
|
||||
},
|
||||
'accordion-up': {
|
||||
from: { height: 'var(--radix-accordion-content-height)' },
|
||||
to: { height: 0 }
|
||||
}
|
||||
},
|
||||
animation: {
|
||||
'accordion-down': 'accordion-down 0.2s ease-out',
|
||||
'accordion-up': 'accordion-up 0.2s ease-out'
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: [require('@tailwindcss/forms')]
|
||||
plugins: [require('tailwindcss-animate'), require('tailwindcss'), require('autoprefixer')]
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue