Compare commits

..

9 Commits

Author SHA1 Message Date
Mus9617
4278f1f0d7 added Packacge TracingBeam
#12
2024-06-07 14:26:29 +02:00
Mus9617
85b62a35f4 Revert "package updated"
This reverts commit 94b07af7e7.
2024-06-07 14:20:16 +02:00
Mus9617
35dcff135f Revert "hero implemented first stape"
This reverts commit ae8cd7f6b4.
2024-06-07 14:19:56 +02:00
Mus9617
ae8cd7f6b4 hero implemented first stape
#12
2024-06-07 13:45:14 +02:00
Mus9617
f2fe965ce6 update gitignore 2024-06-07 12:20:42 +02:00
Mus9617
94b07af7e7 package updated
#12
2024-06-07 12:20:25 +02:00
Mus9617
15558d11ce Revert "package update"
This reverts commit 78d5bd3af6.
2024-06-07 12:17:50 +02:00
Mus9617
78d5bd3af6 package update
#12
2024-06-07 12:15:58 +02:00
Mus9617
8e1a327c6d update gitignore 2024-06-07 12:14:52 +02:00
19 changed files with 315 additions and 2566 deletions

1
.gitignore vendored
View File

@@ -38,3 +38,4 @@ next-env.d.ts
.env.production
.env.development
.env*.local
pnpm*.yaml

View File

@@ -23,7 +23,6 @@
"@radix-ui/react-hover-card": "^1.0.7",
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-menubar": "^1.0.4",
"@radix-ui/react-navigation-menu": "^1.1.4",
"@radix-ui/react-popover": "^1.0.7",
"@radix-ui/react-progress": "^1.0.3",
"@radix-ui/react-radio-group": "^1.1.3",
@@ -46,7 +45,6 @@
"embla-carousel-react": "^8.1.3",
"framer-motion": "^11.2.10",
"input-otp": "^1.2.4",
"lightweight-charts": "^4.1.4",
"lucide-react": "^0.387.0",
"next": "14.2.3",
"next-themes": "^0.3.0",
@@ -62,11 +60,9 @@
"zod": "^3.23.8"
},
"devDependencies": {
"@types/jest": "^29.5.12",
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"jest": "^29.7.0",
"postcss": "^8",
"tailwindcss": "^3.4.1",
"typescript": "^5"

2283
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -5,8 +5,6 @@ import {ThemeProvider} from "@/components/providers/theme-provider";
import type React from "react";
import {Footer} from "@/components/footer";
import {Header} from "@/components/header";
import {PrimaryNavigationMenu} from "@/components/primary-nav";
import {Providers} from "@/components/providers/providers";
export const metadata: Metadata = {
title: "YeloBit",
@@ -23,14 +21,16 @@ export default function RootLayout({
<head>
<link rel="icon" href="/public/favicon.ico" sizes="any"/>
</head>
<body className={"w-full min-h-screen flex flex-col items-center justify-between"}>
<Providers>
<Header>
<PrimaryNavigationMenu/>
</Header>
{children}
<Footer/>
</Providers>
<body className={"w-full min-h-screen flex flex-col items-center justify-between"}>
<ThemeProvider
attribute="class"
defaultTheme="system"
enableSystem
>
<Header></Header>
{children}
<Footer/>
</ThemeProvider>
</body>
</html>
);

View File

@@ -2,7 +2,7 @@ import Image from "next/image";
export default function Home() {
return (
<main className="flex flex-col items-center justify-end h-full w-2/4">
<main className="flex flex-col items-center justify-between p-24">
<h1>Hello world !</h1>
</main>
);

View File

@@ -1,22 +0,0 @@
"use client"
import {useContext} from "react";
import {UserDataContext} from "@/components/providers/userdata-provider";
import {AccountInfo} from "@/components/account-info";
export function AccountDialog() {
const userContext = useContext(UserDataContext)
if (!userContext?.userData) {
userContext?.setUserData({name: "Mathis"})
return (<p>Loading...</p>)
}
//TODO No account context
//TODO Loading context
//TODO Account context
return (<AccountInfo userData={userContext.userData}/>)
}

View File

@@ -1,58 +0,0 @@
"use client"
import {IUserData} from "@/interfaces/userdata.interface";
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import {
Sheet,
SheetClose,
SheetContent,
SheetDescription,
SheetFooter,
SheetHeader,
SheetTitle,
SheetTrigger,
} from "@/components/ui/sheet"
import {User} from "lucide-react";
export function AccountInfo({userData}: {userData: IUserData}) {
return (
<Sheet>
<SheetTrigger asChild>
<Button variant="outline" className={"gap-1"}>
<User />
{userData?.firstName || "?"}
</Button>
</SheetTrigger>
<SheetContent>
<SheetHeader>
<SheetTitle>Edit profile</SheetTitle>
<SheetDescription>
Make changes to your profile here. Click save when you're done.
</SheetDescription>
</SheetHeader>
<div className="grid gap-4 py-4">
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="name" className="text-right">
Name
</Label>
<Input id="name" placeholder={userData.firstName} className="col-span-3" onChange={(event)=>{console.log(event.target.value)}} />
</div>
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="username" className="text-right">
Username
</Label>
<Input id="username" value="@peduarte" className="col-span-3" />
</div>
</div>
<SheetFooter>
<SheetClose asChild>
<Button type="submit">Save changes</Button>
</SheetClose>
</SheetFooter>
</SheetContent>
</Sheet>
)
}

View File

@@ -1,7 +1,6 @@
import Image from "next/image";
import React from "react";
import {ThemeBtnSelector} from "@/components/theme-btn-selector";
import {AccountDialog} from "@/components/account-dialog";
export function Header({title, children}: {title?: string, children?: React.ReactNode}) {
@@ -17,8 +16,7 @@ export function Header({title, children}: {title?: string, children?: React.Reac
<div className={"w-1/3 flex flex-row justify-center items-center"}>
{children}
</div>
<div className={"w-1/3 flex flex-row justify-end gap-2 items-center"}>
<AccountDialog/>
<div className={"w-1/3 flex flex-row justify-end items-center"}>
<ThemeBtnSelector/>
</div>
</header>

117
src/components/hero.tsx Normal file
View File

@@ -0,0 +1,117 @@
"use client";
import React from "react";
import { calsans } from "@/fonts/calsans";
import Image from "next/image";
import { twMerge } from "tailwind-merge";
import { TracingBeam } from "@/components/ui/tracing-beam";
export function TracingBeamDemo() {
return (
<TracingBeam className="px-6">
<div className="max-w-2xl mx-auto antialiased pt-4 relative">
{dummyContent.map((item, index) => (
<div key={`content-${index}`} className="mb-10">
<h2 className="bg-black text-white rounded-full text-sm w-fit px-4 py-1 mb-4">
{item.badge}
</h2>
<p className={twMerge(calsans.className, "text-xl mb-4")}>
{item.title}
</p>
<div className="text-sm prose prose-sm dark:prose-invert">
{item?.image && (
<Image
src={item.image}
alt="blog thumbnail"
height="1000"
width="1000"
className="rounded-lg mb-10 object-cover"
/>
)}
{item.description}
</div>
</div>
))}
</div>
</TracingBeam>
);
}
const dummyContent = [
{
title: "Lorem Ipsum Dolor Sit Amet",
description: (
<>
<p>
Sit duis est minim proident non nisi velit non consectetur. Esse
adipisicing laboris consectetur enim ipsum reprehenderit eu deserunt
Lorem ut aliqua anim do. Duis cupidatat qui irure cupidatat incididunt
incididunt enim magna id est qui sunt fugiat. Laboris do duis pariatur
fugiat Lorem aute sit ullamco. Qui deserunt non reprehenderit dolore
nisi velit exercitation Lorem qui do enim culpa. Aliqua eiusmod in
occaecat reprehenderit laborum nostrud fugiat voluptate do Lorem culpa
officia sint labore. Tempor consectetur excepteur ut fugiat veniam
commodo et labore dolore commodo pariatur.
</p>
<p>
Dolor minim irure ut Lorem proident. Ipsum do pariatur est ad ad
veniam in commodo id reprehenderit adipisicing. Proident duis
exercitation ad quis ex cupidatat cupidatat occaecat adipisicing.
</p>
<p>
Tempor quis dolor veniam quis dolor. Sit reprehenderit eiusmod
reprehenderit deserunt amet laborum consequat adipisicing officia qui
irure id sint adipisicing. Adipisicing fugiat aliqua nulla nostrud.
Amet culpa officia aliquip deserunt veniam deserunt officia
adipisicing aliquip proident officia sunt.
</p>
</>
),
badge: "React",
image:
"https://images.unsplash.com/photo-1464822759023-fed622ff2c3b?auto=format&fit=crop&q=80&w=3540&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
},
{
title: "Lorem Ipsum Dolor Sit Amet",
description: (
<>
<p>
Ex irure dolore veniam ex velit non aute nisi labore ipsum occaecat
deserunt cupidatat aute. Enim cillum dolor et nulla sunt exercitation
non voluptate qui aliquip esse tempor. Ullamco ut sunt consectetur
sint qui qui do do qui do. Labore laborum culpa magna reprehenderit ea
velit id esse adipisicing deserunt amet dolore. Ipsum occaecat veniam
commodo proident aliqua id ad deserunt dolor aliquip duis veniam sunt.
</p>
<p>
In dolore veniam excepteur eu est et sunt velit. Ipsum sint esse
veniam fugiat esse qui sint ad sunt reprehenderit do qui proident
reprehenderit. Laborum exercitation aliqua reprehenderit ea sint
cillum ut mollit.
</p>
</>
),
badge: "Changelog",
image:
"https://images.unsplash.com/photo-1519681393784-d120267933ba?auto=format&fit=crop&q=80&w=3540&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
},
{
title: "Lorem Ipsum Dolor Sit Amet",
description: (
<>
<p>
Ex irure dolore veniam ex velit non aute nisi labore ipsum occaecat
deserunt cupidatat aute. Enim cillum dolor et nulla sunt exercitation
non voluptate qui aliquip esse tempor. Ullamco ut sunt consectetur
sint qui qui do do qui do. Labore laborum culpa magna reprehenderit ea
velit id esse adipisicing deserunt amet dolore. Ipsum occaecat veniam
commodo proident aliqua id ad deserunt dolor aliquip duis veniam sunt.
</p>
</>
),
badge: "Launch Week",
image:
"https://images.unsplash.com/photo-1469474968028-56623f02e42e?auto=format&fit=crop&q=80&w=3506&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
},
];

View File

@@ -1,23 +0,0 @@
"use client"
import React from "react";
import {Header} from "@/components/header";
import {Footer} from "@/components/footer";
import {ThemeProvider} from "@/components/providers/theme-provider";
import {UserDataProvider} from "@/components/providers/userdata-provider";
export function Providers({children}: { children: React.ReactNode }) {
return (
<ThemeProvider
attribute="class"
defaultTheme="system"
enableSystem
>
<UserDataProvider>
{children}
</UserDataProvider>
</ThemeProvider>
)
}

View File

@@ -1,21 +0,0 @@
import React from 'react';
import {IUserData} from "@/interfaces/userdata.interface";
import {useEncodedLocalStorage} from "@/services/localStorage";
export interface IUserDataProvider {
userData: IUserData | undefined;
setUserData: React.Dispatch<React.SetStateAction<IUserData | undefined>>
}
export const UserDataContext = React.createContext<IUserDataProvider | undefined>(undefined);
export const UserDataProvider = ({children}: {children: React.ReactNode}) => {
const [userData, setUserData] = useEncodedLocalStorage<IUserData | undefined>("user_data", undefined);
return (
<UserDataContext.Provider value={{userData, setUserData}}>
{children}
</UserDataContext.Provider>
);
};

View File

@@ -0,0 +1,128 @@
"use client";
import React, { useEffect, useRef, useState } from "react";
import {
motion,
useTransform,
useScroll,
useVelocity,
useSpring,
} from "framer-motion";
import { cn } from "@/lib/utils";
export const TracingBeam = ({
children,
className,
}: {
children: React.ReactNode;
className?: string;
}) => {
const ref = useRef<HTMLDivElement>(null);
const { scrollYProgress } = useScroll({
target: ref,
offset: ["start start", "end start"],
});
const contentRef = useRef<HTMLDivElement>(null);
const [svgHeight, setSvgHeight] = useState(0);
useEffect(() => {
if (contentRef.current) {
setSvgHeight(contentRef.current.offsetHeight);
}
}, []);
const y1 = useSpring(
useTransform(scrollYProgress, [0, 0.8], [50, svgHeight]),
{
stiffness: 500,
damping: 90,
}
);
const y2 = useSpring(
useTransform(scrollYProgress, [0, 1], [50, svgHeight - 200]),
{
stiffness: 500,
damping: 90,
}
);
return (
<motion.div
ref={ref}
className={cn("relative w-full max-w-4xl mx-auto h-full", className)}
>
<div className="absolute -left-4 md:-left-20 top-3">
<motion.div
transition={{
duration: 0.2,
delay: 0.5,
}}
animate={{
boxShadow:
scrollYProgress.get() > 0
? "none"
: "rgba(0, 0, 0, 0.24) 0px 3px 8px",
}}
className="ml-[27px] h-4 w-4 rounded-full border border-netural-200 shadow-sm flex items-center justify-center"
>
<motion.div
transition={{
duration: 0.2,
delay: 0.5,
}}
animate={{
backgroundColor:
scrollYProgress.get() > 0 ? "white" : "var(--emerald-500)",
borderColor:
scrollYProgress.get() > 0 ? "white" : "var(--emerald-600)",
}}
className="h-2 w-2 rounded-full border border-neutral-300 bg-white"
/>
</motion.div>
<svg
viewBox={`0 0 20 ${svgHeight}`}
width="20"
height={svgHeight} // Set the SVG height
className=" ml-4 block"
aria-hidden="true"
>
<motion.path
d={`M 1 0V -36 l 18 24 V ${svgHeight * 0.8} l -18 24V ${svgHeight}`}
fill="none"
stroke="#9091A0"
strokeOpacity="0.16"
transition={{
duration: 10,
}}
></motion.path>
<motion.path
d={`M 1 0V -36 l 18 24 V ${svgHeight * 0.8} l -18 24V ${svgHeight}`}
fill="none"
stroke="url(#gradient)"
strokeWidth="1.25"
className="motion-reduce:hidden"
transition={{
duration: 10,
}}
></motion.path>
<defs>
<motion.linearGradient
id="gradient"
gradientUnits="userSpaceOnUse"
x1="0"
x2="0"
y1={y1} // set y1 for gradient
y2={y2} // set y2 for gradient
>
<stop stopColor="#18CCFC" stopOpacity="0"></stop>
<stop stopColor="#18CCFC"></stop>
<stop offset="0.325" stopColor="#6344F5"></stop>
<stop offset="1" stopColor="#AE48FF" stopOpacity="0"></stop>
</motion.linearGradient>
</defs>
</svg>
</div>
<div ref={contentRef}>{children}</div>
</motion.div>
);
};

View File

@@ -1,36 +0,0 @@
import {IUserData} from "@/interfaces/userdata.interface";
// ----- Request -----
export interface IApiRegisterReq {
firstName: string;
lastName: string;
pseudo: string;
city: string;
email: string;
password: string;
age: number;
}
export interface IApiLoginReq {
email: string;
password: string;
}
// ----- Response -----
export interface IAbstractApiResponse {
message?: Array<string>;
error?: string;
statusCode?: number
}
export interface IApiRegisterRes extends IAbstractApiResponse {
access_token?: string;
user?: IUserData
}
export interface IApiLoginRes extends IAbstractApiResponse {
access_token?: string
}

View File

@@ -1,14 +0,0 @@
export interface IUserData {
id: string;
firstName: string;
lastName: string;
pseudo: string;
email: string;
roleId: string;
isActive: boolean;
city: string;
dollarAvailables: number;
age: number;
created_at: string;
updated_at: string;
}

View File

@@ -1,55 +0,0 @@
"use client"
import { createContext, useContext, useState } from 'react';
import {IUserData} from "@/interfaces/userdata.interface";
import {IApiLoginReq, IApiLoginRes, IApiRegisterReq, IApiRegisterRes} from "@/interfaces/api.interface";
import ApiRequest from "@/services/apiRequest";
import {useEncodedLocalStorage} from "@/services/localStorage";
const UserDataContext = createContext<IUserData | null>(null)
const [userData, setUserData] = useEncodedLocalStorage<IUserData | null>("user_data", null)
//TODO Run register task
export async function doRegister(registerData: IApiRegisterReq): Promise<IApiRegisterRes | null> {
console.trace(registerData)
try {
const ReqRes = await ApiRequest.standard.post.json<IApiRegisterReq, IApiRegisterRes>("auth/signup", registerData)
console.trace(ReqRes.data)
if (ReqRes.data.user) {
setUserData(ReqRes.data.user)
}
ReqRes.data.message?.forEach((err)=> console.warn(err))
return ReqRes.data
} catch (error) {
console.error('Error during registration:', error);
return null
}
}
//TODO Run login task
export async function doLogin(loginData: IApiLoginReq) {
try {
const ReqRes = await ApiRequest.standard.post.json<IApiLoginReq, IApiLoginRes>("auth/login", loginData)
console.trace(ReqRes.data)
//if (ReqRes.data.user) {
// setUserData(ReqRes.data.user)
//}
ReqRes.data.message?.forEach((err)=> console.warn(err))
return ReqRes.data
} catch (err) {
console.error('Error during login:', err);
return null
}
}
//TODO Run disconnect task
export function doDisconnect() {
if (typeof window !== 'undefined') {
window.localStorage.removeItem('sub')
return true
}
console.log('Whut ? Why trying to remove an item from the localStorage when runner in SSR ?')
return false
}
//TODO Run update user data

View File

@@ -2,7 +2,7 @@
import axios, {type AxiosResponse} from "axios";
const baseUrl = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3333'
const baseUrl = ""
const AxiosConfigs = {
authenticated: {
@@ -10,7 +10,7 @@ const AxiosConfigs = {
return {
headers: {
'content-type': 'application/json',
Authorization: `Bearer ${typeof window !== 'undefined' ? window.localStorage.getItem('sub') : "not-ssr"}`,
Authorization: `Bearer ${localStorage.getItem('sub')}`,
},
validateStatus: function (status: number) {
return status < 500; // Resolve only if the status code is less than 500
@@ -32,30 +32,72 @@ const AxiosConfigs = {
}
}
async function doAuthenticatedJsonPostReq<ReqT, ResT>(route:string, body:ReqT): Promise<AxiosResponse<ResT>> {
/**
* Makes an authenticated JSON POST request using axios.
* @param {string} route - The route to send the request to.
* @param {object} body - The request body.
* @returns {Promise<AxiosResponse<ReqT, ResT>>} - The promise that resolves to the response from the server.
*/
async function doAuthenticatedJsonPostReq<ReqT, ResT>(route:string, body:object): Promise<AxiosResponse<ReqT, ResT>> {
return await axios.post(baseUrl + route, body, AxiosConfigs.authenticated.json())
}
async function doAuthenticatedGetReq<ResT>(route:string): Promise<AxiosResponse<ResT>> {
/**
* Makes an authenticated GET request to the specified route using Axios.
*
* @param {string} route - The route to which the GET request is sent.
* @returns {Promise<AxiosResponse>} - A promise that resolves to the Axios response object containing the request data and response details.
*/
async function doAuthenticatedGetReq<ReqT, ResT>(route:string): Promise<AxiosResponse<ReqT, ResT>> {
return await axios.get(baseUrl + route, AxiosConfigs.authenticated.json())
}
async function doAuthenticatedPatchReq<ReqT, ResT>(route:string, body: ReqT): Promise<AxiosResponse<ResT>> {
/**
* Performs an authenticated PATCH request to the specified route with the given body.
*
* @param {string} route - The route to send the PATCH request to.
* @param {object} body - The body of the request.
* @returns {Promise<AxiosResponse<ReqT, ResT>>} - A Promise that resolves to the AxiosResponse object containing the response data.
*/
async function doAuthenticatedPatchReq<ReqT, ResT>(route:string, body: object): Promise<AxiosResponse<ReqT, ResT>> {
return await axios.patch(baseUrl + route, body, AxiosConfigs.authenticated.json())
}
async function doAuthenticatedDelReq<ResT>(route:string): Promise<AxiosResponse<ResT>> {
/**
* Sends an authenticated DELETE request to the specified route.
*
* @param {string} route - The route to send the request to.
*
* @return {Promise<AxiosResponse<ReqT, ResT>>} A Promise that resolves to the AxiosResponse object containing the response data.
*/
async function doAuthenticatedDelReq<ReqT, ResT>(route:string): Promise<AxiosResponse<ReqT, ResT>> {
return await axios.delete(baseUrl + route, AxiosConfigs.authenticated.json())
}
//TODO form/multipart req
async function doJsonPostReq<ReqT, ResT>(route:string, body: ReqT): Promise<AxiosResponse<ResT>> {
/**
* Perform a JSON POST request.
*
* @param {string} route - The route to send the request to.
* @param {object} body - The JSON object to send in the request body.
*
* @return {Promise<AxiosResponse<ReqT, ResT>>} - A promise that resolves with the response from the server.
*
* @throws {Error} - If an error occurs during the request.
*/
async function doJsonPostReq<ReqT, ResT>(route:string, body: object): Promise<AxiosResponse<ReqT, ResT>> {
return await axios.post(baseUrl + route, body, AxiosConfigs.standard.json())
}
async function doJsonGetReq<ResT>(route:string): Promise<AxiosResponse<ResT>> {
/**
* Perform a JSON GET request using Axios.
*
* @param {string} route - The route URL to make the GET request to.
* @returns {Promise<AxiosResponse<ReqT, ResT>>} - A promise that resolves to the AxiosResponse object.
*/
async function doJsonGetReq<ReqT, ResT>(route:string): Promise<AxiosResponse<ReqT, ResT>> {
return await axios.get(baseUrl + route, AxiosConfigs.standard.json());
}

View File

@@ -1,6 +1,6 @@
'use client'
import React, {useEffect, useRef, useState} from "react";
import React, {useEffect, useState} from "react";
/**
* A custom React hook that allows you to store and retrieve data in the browser's localStorage.
@@ -48,20 +48,12 @@ export function useLocalStorage<T>(key: string, initial: T): [T, React.Dispatch<
* @return {readonly [T, React.Dispatch<React.SetStateAction<T>>]} - An array containing the encoded value and a function to update the encoded value.
*/
export function useEncodedLocalStorage<T>(key: string, fallbackValue: T): readonly [T, React.Dispatch<React.SetStateAction<T>>] {
console.log("Pong !")
const [encodedValue, setEncodedValue] = useState<T>(() => {
const stored = localStorage.getItem(key);
return stored ? safelyParse(stored, fallbackValue) : fallbackValue;
});
const prevValue = useRef(encodedValue);
useEffect(() => {
console.log({encodedValue})
if (!b64ValEqual(prevValue.current, encodedValue)) {
localStorage.setItem(key, safelyStringify(encodedValue));
}
prevValue.current = encodedValue; // Set ref to current value
localStorage.setItem(key, safelyStringify(encodedValue));
}, [key, encodedValue]);
return [encodedValue, setEncodedValue] as const;
@@ -72,12 +64,6 @@ export function useEncodedLocalStorage<T>(key: string, fallbackValue: T): readon
return fallback;
}
}
function b64ValEqual<T>(v1: T, v2: T): boolean {
return btoa(JSON.stringify(v1)) === btoa(JSON.stringify(v2));
}
function safelyStringify(value: T): string {
try {
return btoa(JSON.stringify(value));

View File

@@ -1,8 +1,5 @@
import type { Config } from "tailwindcss"
// @ts-ignore
import {default as flattenColorPalette} from "tailwindcss/lib/util/flattenColorPalette";
const config = {
darkMode: ["class"],
content: [
@@ -77,19 +74,7 @@ const config = {
},
},
},
plugins: [require("tailwindcss-animate"), addVariablesForColors],
plugins: [require("tailwindcss-animate")],
} satisfies Config
// This plugin adds each Tailwind color as a global CSS variable, e.g. var(--gray-200).
function addVariablesForColors({ addBase, theme }: any) {
let allColors = flattenColorPalette(theme("colors"));
let newVars = Object.fromEntries(
Object.entries(allColors).map(([key, val]) => [`--${key}`, val])
);
addBase({
":root": newVars,
});
}
export default config