Compare commits
	
		
			10 Commits
		
	
	
		
			afc8530b43
			...
			master
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | ec040d8318 | ||
|  | ba998eb401 | ||
|  | 346e79622d | ||
|  | c754d1de6e | ||
|  | fd08431f7b | ||
|  | b35d8f76df | ||
|  | 4f35ed1abd | ||
|  | 4f0646dd2a | ||
|  | 109da1bd33 | ||
|  | c1cfda32f8 | 
							
								
								
									
										12
									
								
								api/drizzle.config.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								api/drizzle.config.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| import { defineConfig } from 'drizzle-kit'; | ||||
|  | ||||
| export default defineConfig({ | ||||
|   out: './drizzle', | ||||
|   schema: ['./src/db/productsSchema.ts', './src/db/usersSchema.ts'], | ||||
|   dialect: 'mysql', | ||||
|   dbCredentials: { | ||||
|     url: process.env.DATABASE_URL!, | ||||
|   }, | ||||
|   verbose: true, | ||||
|   strict: true, | ||||
| }); | ||||
							
								
								
									
										8
									
								
								api/drizzle/0000_spooky_dormammu.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								api/drizzle/0000_spooky_dormammu.sql
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| CREATE TABLE `products` ( | ||||
| 	`id` int AUTO_INCREMENT NOT NULL, | ||||
| 	`name` varchar(255) NOT NULL, | ||||
| 	`description` text, | ||||
| 	`image` varchar(255), | ||||
| 	`price` double NOT NULL, | ||||
| 	CONSTRAINT `products_id` PRIMARY KEY(`id`) | ||||
| ); | ||||
							
								
								
									
										10
									
								
								api/drizzle/0001_peaceful_carnage.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								api/drizzle/0001_peaceful_carnage.sql
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| CREATE TABLE `users` ( | ||||
| 	`id` int AUTO_INCREMENT NOT NULL, | ||||
| 	`email` varchar(255) NOT NULL, | ||||
| 	`password` varchar(255) NOT NULL, | ||||
| 	`role` varchar(255) NOT NULL DEFAULT 'user', | ||||
| 	`name` varchar(255) NOT NULL, | ||||
| 	`address` text, | ||||
| 	CONSTRAINT `users_id` PRIMARY KEY(`id`), | ||||
| 	CONSTRAINT `users_email_unique` UNIQUE(`email`) | ||||
| ); | ||||
							
								
								
									
										70
									
								
								api/drizzle/meta/0000_snapshot.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								api/drizzle/meta/0000_snapshot.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,70 @@ | ||||
| { | ||||
|   "version": "5", | ||||
|   "dialect": "mysql", | ||||
|   "id": "145ca097-6129-4cdc-aa8c-00b6057bf887", | ||||
|   "prevId": "00000000-0000-0000-0000-000000000000", | ||||
|   "tables": { | ||||
|     "products": { | ||||
|       "name": "products", | ||||
|       "columns": { | ||||
|         "id": { | ||||
|           "name": "id", | ||||
|           "type": "int", | ||||
|           "primaryKey": false, | ||||
|           "notNull": true, | ||||
|           "autoincrement": true | ||||
|         }, | ||||
|         "name": { | ||||
|           "name": "name", | ||||
|           "type": "varchar(255)", | ||||
|           "primaryKey": false, | ||||
|           "notNull": true, | ||||
|           "autoincrement": false | ||||
|         }, | ||||
|         "description": { | ||||
|           "name": "description", | ||||
|           "type": "text", | ||||
|           "primaryKey": false, | ||||
|           "notNull": false, | ||||
|           "autoincrement": false | ||||
|         }, | ||||
|         "image": { | ||||
|           "name": "image", | ||||
|           "type": "varchar(255)", | ||||
|           "primaryKey": false, | ||||
|           "notNull": false, | ||||
|           "autoincrement": false | ||||
|         }, | ||||
|         "price": { | ||||
|           "name": "price", | ||||
|           "type": "double", | ||||
|           "primaryKey": false, | ||||
|           "notNull": true, | ||||
|           "autoincrement": false | ||||
|         } | ||||
|       }, | ||||
|       "indexes": {}, | ||||
|       "foreignKeys": {}, | ||||
|       "compositePrimaryKeys": { | ||||
|         "products_id": { | ||||
|           "name": "products_id", | ||||
|           "columns": [ | ||||
|             "id" | ||||
|           ] | ||||
|         } | ||||
|       }, | ||||
|       "uniqueConstraints": {}, | ||||
|       "checkConstraint": {} | ||||
|     } | ||||
|   }, | ||||
|   "views": {}, | ||||
|   "_meta": { | ||||
|     "schemas": {}, | ||||
|     "tables": {}, | ||||
|     "columns": {} | ||||
|   }, | ||||
|   "internal": { | ||||
|     "tables": {}, | ||||
|     "indexes": {} | ||||
|   } | ||||
| } | ||||
							
								
								
									
										137
									
								
								api/drizzle/meta/0001_snapshot.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								api/drizzle/meta/0001_snapshot.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,137 @@ | ||||
| { | ||||
|   "version": "5", | ||||
|   "dialect": "mysql", | ||||
|   "id": "2c28ca58-2027-4c36-8c76-dae7fdda9cad", | ||||
|   "prevId": "145ca097-6129-4cdc-aa8c-00b6057bf887", | ||||
|   "tables": { | ||||
|     "products": { | ||||
|       "name": "products", | ||||
|       "columns": { | ||||
|         "id": { | ||||
|           "name": "id", | ||||
|           "type": "int", | ||||
|           "primaryKey": false, | ||||
|           "notNull": true, | ||||
|           "autoincrement": true | ||||
|         }, | ||||
|         "name": { | ||||
|           "name": "name", | ||||
|           "type": "varchar(255)", | ||||
|           "primaryKey": false, | ||||
|           "notNull": true, | ||||
|           "autoincrement": false | ||||
|         }, | ||||
|         "description": { | ||||
|           "name": "description", | ||||
|           "type": "text", | ||||
|           "primaryKey": false, | ||||
|           "notNull": false, | ||||
|           "autoincrement": false | ||||
|         }, | ||||
|         "image": { | ||||
|           "name": "image", | ||||
|           "type": "varchar(255)", | ||||
|           "primaryKey": false, | ||||
|           "notNull": false, | ||||
|           "autoincrement": false | ||||
|         }, | ||||
|         "price": { | ||||
|           "name": "price", | ||||
|           "type": "double", | ||||
|           "primaryKey": false, | ||||
|           "notNull": true, | ||||
|           "autoincrement": false | ||||
|         } | ||||
|       }, | ||||
|       "indexes": {}, | ||||
|       "foreignKeys": {}, | ||||
|       "compositePrimaryKeys": { | ||||
|         "products_id": { | ||||
|           "name": "products_id", | ||||
|           "columns": [ | ||||
|             "id" | ||||
|           ] | ||||
|         } | ||||
|       }, | ||||
|       "uniqueConstraints": {}, | ||||
|       "checkConstraint": {} | ||||
|     }, | ||||
|     "users": { | ||||
|       "name": "users", | ||||
|       "columns": { | ||||
|         "id": { | ||||
|           "name": "id", | ||||
|           "type": "int", | ||||
|           "primaryKey": false, | ||||
|           "notNull": true, | ||||
|           "autoincrement": true | ||||
|         }, | ||||
|         "email": { | ||||
|           "name": "email", | ||||
|           "type": "varchar(255)", | ||||
|           "primaryKey": false, | ||||
|           "notNull": true, | ||||
|           "autoincrement": false | ||||
|         }, | ||||
|         "password": { | ||||
|           "name": "password", | ||||
|           "type": "varchar(255)", | ||||
|           "primaryKey": false, | ||||
|           "notNull": true, | ||||
|           "autoincrement": false | ||||
|         }, | ||||
|         "role": { | ||||
|           "name": "role", | ||||
|           "type": "varchar(255)", | ||||
|           "primaryKey": false, | ||||
|           "notNull": true, | ||||
|           "autoincrement": false, | ||||
|           "default": "'user'" | ||||
|         }, | ||||
|         "name": { | ||||
|           "name": "name", | ||||
|           "type": "varchar(255)", | ||||
|           "primaryKey": false, | ||||
|           "notNull": true, | ||||
|           "autoincrement": false | ||||
|         }, | ||||
|         "address": { | ||||
|           "name": "address", | ||||
|           "type": "text", | ||||
|           "primaryKey": false, | ||||
|           "notNull": false, | ||||
|           "autoincrement": false | ||||
|         } | ||||
|       }, | ||||
|       "indexes": {}, | ||||
|       "foreignKeys": {}, | ||||
|       "compositePrimaryKeys": { | ||||
|         "users_id": { | ||||
|           "name": "users_id", | ||||
|           "columns": [ | ||||
|             "id" | ||||
|           ] | ||||
|         } | ||||
|       }, | ||||
|       "uniqueConstraints": { | ||||
|         "users_email_unique": { | ||||
|           "name": "users_email_unique", | ||||
|           "columns": [ | ||||
|             "email" | ||||
|           ] | ||||
|         } | ||||
|       }, | ||||
|       "checkConstraint": {} | ||||
|     } | ||||
|   }, | ||||
|   "views": {}, | ||||
|   "_meta": { | ||||
|     "schemas": {}, | ||||
|     "tables": {}, | ||||
|     "columns": {} | ||||
|   }, | ||||
|   "internal": { | ||||
|     "tables": {}, | ||||
|     "indexes": {} | ||||
|   } | ||||
| } | ||||
							
								
								
									
										20
									
								
								api/drizzle/meta/_journal.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								api/drizzle/meta/_journal.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| { | ||||
|   "version": "7", | ||||
|   "dialect": "mysql", | ||||
|   "entries": [ | ||||
|     { | ||||
|       "idx": 0, | ||||
|       "version": "5", | ||||
|       "when": 1751792977207, | ||||
|       "tag": "0000_spooky_dormammu", | ||||
|       "breakpoints": true | ||||
|     }, | ||||
|     { | ||||
|       "idx": 1, | ||||
|       "version": "5", | ||||
|       "when": 1752400394255, | ||||
|       "tag": "0001_peaceful_carnage", | ||||
|       "breakpoints": true | ||||
|     } | ||||
|   ] | ||||
| } | ||||
							
								
								
									
										925
									
								
								api/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										925
									
								
								api/package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -8,14 +8,29 @@ | ||||
|   "main": "index.js", | ||||
|   "scripts": { | ||||
|     "test": "echo \"Error: no test specified\" && exit 1", | ||||
|     "dev" : "node --import=tsx --watch --env-file=.env src/index.ts", | ||||
|     "build": "tsc" | ||||
|     "dev": "node --import=tsx --watch --env-file=.env src/index.ts", | ||||
|     "build": "tsc", | ||||
|     "db:generate": "drizzle-kit generate", | ||||
|     "db:migrate": "drizzle-kit migrate", | ||||
|     "db:push": "drizzle-kit push", | ||||
|     "db:studio": "drizzle-kit studio" | ||||
|   }, | ||||
|   "dependencies": { | ||||
|     "express": "^5.1.0" | ||||
|     "bcryptjs": "^3.0.2", | ||||
|     "drizzle-orm": "^0.44.2", | ||||
|     "drizzle-zod": "^0.8.2", | ||||
|     "express": "^5.1.0", | ||||
|     "jsonwebtoken": "^9.0.2", | ||||
|     "lodash": "^4.17.21", | ||||
|     "mysql2": "^3.14.1", | ||||
|     "zod": "^3.25.74" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "@types/bcryptjs": "^2.4.6", | ||||
|     "@types/express": "^5.0.3", | ||||
|     "@types/jsonwebtoken": "^9.0.10", | ||||
|     "@types/lodash": "^4.17.20", | ||||
|     "drizzle-kit": "^0.31.4", | ||||
|     "tsx": "^4.20.3", | ||||
|     "typescript": "^5.8.3" | ||||
|   } | ||||
|   | ||||
							
								
								
									
										4
									
								
								api/src/db/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								api/src/db/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | ||||
| import { drizzle } from "drizzle-orm/mysql2"; | ||||
|  | ||||
| // You can specify any property from the mysql2 connection options | ||||
| export const db = drizzle({ connection: { uri: process.env.DATABASE_URL }}); | ||||
							
								
								
									
										25
									
								
								api/src/db/productsSchema.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								api/src/db/productsSchema.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| import { int, mysqlTable, text, bigint, varchar, double } from 'drizzle-orm/mysql-core'; | ||||
| import { createInsertSchema , createSelectSchema, createUpdateSchema } from 'drizzle-zod'; | ||||
|  | ||||
| export const productsTable = mysqlTable('products', { | ||||
|   id: int().autoincrement().primaryKey(), | ||||
|   name: varchar({ length: 255 }).notNull(), | ||||
|   description: text(), | ||||
|   image: varchar({ length: 255 }), | ||||
|   price: double().notNull(), | ||||
| }); | ||||
|  | ||||
|  | ||||
| // const createProductSchema = z.object({ | ||||
| //     name: z.string(), | ||||
| //     price: z.number({ message: "not a number you idiot."}), | ||||
| // }); | ||||
|  | ||||
| export const createProductSchema = createInsertSchema(productsTable).omit({ | ||||
|   id: true, | ||||
| }); | ||||
|  | ||||
| export const updateProductSchema = createUpdateSchema(productsTable).omit({ | ||||
|   id: true, | ||||
| }) | ||||
| .partial(); | ||||
							
								
								
									
										3
									
								
								api/src/db/schema.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								api/src/db/schema.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| import * as productsSchema from './productsSchema'; | ||||
|  | ||||
| export default {...productsSchema}; | ||||
							
								
								
									
										23
									
								
								api/src/db/usersSchema.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								api/src/db/usersSchema.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| import { int, mysqlTable, text, bigint, varchar, double } from 'drizzle-orm/mysql-core'; | ||||
| import { createInsertSchema , createSelectSchema, createUpdateSchema } from 'drizzle-zod'; | ||||
|  | ||||
| export const usersTable = mysqlTable('users', { | ||||
|   id: int().autoincrement().primaryKey(), | ||||
|   email: varchar({ length: 255 }).notNull().unique(), | ||||
|   password: varchar({ length: 255 }).notNull(), | ||||
|   role: varchar({ length: 255 }).notNull().default('user'), | ||||
|  | ||||
|   name: varchar({ length: 255 }).notNull(), | ||||
|   address: text(), | ||||
|  | ||||
| }); | ||||
|  | ||||
| export const createUserSchema = createInsertSchema(usersTable).omit({ | ||||
|   id: true, | ||||
|   role: true, | ||||
| }); | ||||
|  | ||||
| export const loginSchema = createSelectSchema(usersTable).pick({ | ||||
|   email: true, | ||||
|   password: true, | ||||
| }); | ||||
| @@ -1,18 +1,25 @@ | ||||
| import express from 'express'; | ||||
| import ProductsRoutes from './routes/products/index' | ||||
| import express, {json, urlencoded} from 'express'; | ||||
| import productsRoutes from './routes/products/index' | ||||
| import authRoutes from './routes/auth/index' | ||||
|  | ||||
| const app = express(); | ||||
| const port = 3000; | ||||
|   | ||||
| const app = express(); | ||||
|  | ||||
| //this is where you put middleware | ||||
| app.use(urlencoded({extended: false})); | ||||
| app.use(json()); // you need to parse the req.body to use it. | ||||
|  | ||||
|  | ||||
| app.get('/', (req, res) => { | ||||
|   res.send('Hello World! 123'); | ||||
|   res.send('Hello World! 1234'); | ||||
| }); | ||||
|  | ||||
|  | ||||
| app.use ('/products', ProductsRoutes); | ||||
| app.use ('/products', productsRoutes); | ||||
| app.use ('/auth', authRoutes); | ||||
|  | ||||
| app.listen(port, () => { | ||||
|   console.log(`Example app listening on port ${port}`); | ||||
| }); | ||||
|  | ||||
| // comment test | ||||
| // comment test  | ||||
							
								
								
									
										35
									
								
								api/src/middlewares/authMiddleware.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								api/src/middlewares/authMiddleware.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| import { Request, Response, NextFunction } from 'express'; | ||||
| import jwt from 'jsonwebtoken'; | ||||
|  | ||||
| export function verifyToken(req: Request, res: Response, next: NextFunction) { | ||||
|     const token = req.header('Authorization'); | ||||
|  | ||||
|     if (!token) { | ||||
|         res.status(401).json({error: "Access denied"}); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     try { | ||||
|         const decoded = jwt.verify(token, 'your-secret'); | ||||
|         if (typeof decoded !== 'object' || !decoded?.userId) { | ||||
|             res.status(401).json({error: "Access denied"}); | ||||
|             return; | ||||
|         } | ||||
|         req.role = decoded.role; | ||||
|         req.userId = decoded.userId; | ||||
|         console.log(decoded); | ||||
|         next(); | ||||
|     } catch (e) { | ||||
|         res.status(401).json({error: "Access denied"}); | ||||
|          | ||||
|     } | ||||
| }; | ||||
|  | ||||
| export function verifySeller(req: Request, res: Response, next: NextFunction) { | ||||
|     const role = req.role; | ||||
|     if (role !== 'seller') { | ||||
|         res.status(401).json({error: "Access denied"}); | ||||
|         return; | ||||
|     } | ||||
|     next(); | ||||
| }; | ||||
							
								
								
									
										25
									
								
								api/src/middlewares/validationMiddleware.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								api/src/middlewares/validationMiddleware.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| import { Request, Response, NextFunction } from 'express'; | ||||
| import { z, ZodError, ZodTypeAny } from 'zod'; | ||||
| import { ZodObject } from 'zod/v4'; | ||||
| import _ from 'lodash'; | ||||
|  | ||||
| export function validateData(schema: ZodObject) { | ||||
|   return (req: Request, res: Response, next: NextFunction) => { | ||||
|     try { | ||||
|       schema.parse(req.body); | ||||
|       req.cleanBody = _.pick(req.body, Object.keys(schema.shape)); | ||||
|       next(); | ||||
|     } catch (error) { | ||||
|       // console.log(error); | ||||
|       if (error instanceof ZodError) { | ||||
|         const errorMessages = error.errors.map((issue: any) => ({ | ||||
|           message: `${issue.path.join('.')} is ${issue.message}`, | ||||
|         })); | ||||
|         res.status(400).json({ error: 'Invalid data', details: errorMessages }); | ||||
|       } else { | ||||
|         const er = error as ZodError | ||||
|         res.status(400).json({ error: er.flatten()}); | ||||
|       } | ||||
|     } | ||||
|   }; | ||||
| } | ||||
							
								
								
									
										72
									
								
								api/src/routes/auth/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								api/src/routes/auth/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | ||||
| import { createUserSchema, loginSchema, usersTable } from "../../db/usersSchema"; | ||||
| import { validateData } from "../../middlewares/validationMiddleware"; | ||||
| import { Router } from "express"; | ||||
| import {db} from '../../db/index'; | ||||
| import {eq} from 'drizzle-orm'; | ||||
| import bcrypt from 'bcryptjs'; | ||||
| import jwt from 'jsonwebtoken' | ||||
|  | ||||
| const router = Router(); | ||||
|  | ||||
| router.post ("/register", validateData(createUserSchema), async (req, res) => { | ||||
|     try{  | ||||
|         console.log (req.cleanBody); | ||||
|         const data = req.cleanBody; | ||||
|         data.password = await bcrypt.hash(data.password, 10); | ||||
|  | ||||
|         const userId = await db | ||||
|                 .insert(usersTable) | ||||
|                 .values(data) | ||||
|                 .$returningId(); | ||||
|  | ||||
|         // const [user] = await db | ||||
|         //         .select() | ||||
|         //         .from(usersTable) | ||||
|         //         .where(eq(usersTable.id, userId)); | ||||
|  | ||||
|         res.status(201).json({userId}); | ||||
|         return; | ||||
|     }catch(e){ | ||||
|         res.status(500); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
| }); | ||||
|  | ||||
| router.post ("/login", validateData(loginSchema) , async (req, res) => { | ||||
|     try{ | ||||
|         const {email, password} = req.cleanBody; | ||||
|         console.log ({email, password}); | ||||
|         const [user] = await db | ||||
|                 .select() | ||||
|                 .from(usersTable) | ||||
|                 .where(eq(usersTable.email, email)); | ||||
|         console.log(user); | ||||
|         if (!user){ | ||||
|             res.status(401).json({error: "Authentication error"}); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         const matched = await bcrypt.compare(password, user.password); | ||||
|         console.log(matched); | ||||
|         if (!matched){ | ||||
|             res.status(401).json({error: "Authentication error"}); | ||||
|             return;            | ||||
|         } | ||||
|  | ||||
|         const token = jwt.sign( | ||||
|             {userId: user.id, role: user.role},  | ||||
|             'your-secret', | ||||
|             {expiresIn: '12h'} | ||||
|         ); | ||||
|         //@ts-ignore | ||||
|         delete user.password; | ||||
|         res.status(200).json({token, user}); | ||||
|     }catch(e){ | ||||
|         res.status(500); | ||||
|         return; | ||||
|     } | ||||
| }); | ||||
|  | ||||
|  | ||||
| export default router; | ||||
| @@ -5,14 +5,21 @@ import { listProducts, | ||||
|     updateProduct,  | ||||
|     deleteProduct  | ||||
| } from "./productsController"; | ||||
| import { validateData } from "../../middlewares/validationMiddleware"; | ||||
| import { z, ZodObject, ZodTypeAny } from 'zod/v4'; | ||||
| import { productsTable, createProductSchema, updateProductSchema } from "../../db/productsSchema"; | ||||
| import { verifySeller, verifyToken } from "../../middlewares/authMiddleware"; | ||||
|  | ||||
|  | ||||
| type ProductType = z.infer<typeof createProductSchema>; | ||||
|  | ||||
| const router = Router(); | ||||
|  | ||||
| // products endpoints | ||||
| // products endpoints where validator can be added later | ||||
| router.get('/', listProducts); | ||||
| router.get('/:id', getProductById); | ||||
| router.post('/', createProduct); | ||||
| router.put('/:id', updateProduct); | ||||
| router.delete('/:id', deleteProduct); | ||||
| router.post('/', verifyToken, verifySeller, validateData(createProductSchema), createProduct); | ||||
| router.put('/:id', verifyToken, verifySeller, validateData(updateProductSchema), updateProduct); | ||||
| router.delete('/:id', verifyToken, verifySeller, deleteProduct); | ||||
|  | ||||
| export default router; | ||||
| @@ -1,21 +1,81 @@ | ||||
| import {Request, Response} from 'express'; | ||||
| import {db} from '../../db/index'; | ||||
| import {eq} from 'drizzle-orm'; | ||||
| import { productsTable, createProductSchema } from "../../db/productsSchema"; | ||||
| import _ from 'lodash'; | ||||
|  | ||||
| export function listProducts(req: Request, res: Response) { | ||||
|     res.send ('listProducts'); | ||||
|  | ||||
|  | ||||
| export async function listProducts(req: Request, res: Response) { | ||||
|     try{ | ||||
|         const products = await db.select().from(productsTable); | ||||
|         res.json(products); | ||||
|     } catch (e) { | ||||
|         res.status(500).send(e); | ||||
|     } | ||||
| } | ||||
|  | ||||
| export function getProductById(req: Request, res: Response) { | ||||
|     res.send ('getProductById'); | ||||
| export async function getProductById(req: Request, res: Response) { | ||||
|     try{ | ||||
|         const {id} = req.params; | ||||
|         const product = await db | ||||
|             .select() | ||||
|             .from(productsTable) | ||||
|             .where(eq(productsTable.id, Number(id))); | ||||
|         if (product.length == 0) { | ||||
|             res.status(404).send({message: "Product not found"}); | ||||
|         } else { | ||||
|             res.json(product); | ||||
|         } | ||||
|         //console.log(product.length); | ||||
|  | ||||
|     } catch (e) { | ||||
|         res.status(500).send(e); | ||||
|     } | ||||
| } | ||||
|  | ||||
| export function createProduct(req: Request, res: Response) { | ||||
|     res.send ('createProduct'); | ||||
| export async function createProduct(req: Request, res: Response) { | ||||
|     try{ | ||||
|         console.log("req.userID = " + req.userId); | ||||
|         const productId = await db | ||||
|         .insert(productsTable) | ||||
|         .values(req.cleanBody) | ||||
|         .$returningId() | ||||
|         //const [product] = await db.insert(productsTable).values(req.body).Returning() | ||||
|         //Postgresql can return series of products so we can capture the first one from array[] | ||||
|         res.status(201).json(productId); | ||||
|     } catch (e) { | ||||
|         res.status(500).send(e); | ||||
|     } | ||||
| } | ||||
|  | ||||
| export function updateProduct(req: Request, res: Response) { | ||||
|     res.send ('updateProduct'); | ||||
| export async function updateProduct(req: Request, res: Response) { | ||||
|     try{ | ||||
|         const id = Number(req.params.id); | ||||
|         const updatedFields = req.cleanBody; | ||||
|  | ||||
|         const result = await db | ||||
|             .update(productsTable) | ||||
|             .set(updatedFields) | ||||
|             .where(eq(productsTable.id, id)) | ||||
|  | ||||
|         console.log(result); | ||||
|  | ||||
|     } catch (e) { | ||||
|         res.status(500).send(e); | ||||
|     } | ||||
| } | ||||
|  | ||||
| export function deleteProduct(req: Request, res: Response) { | ||||
|     res.send ('deleteProduct'); | ||||
| export async function deleteProduct(req: Request, res: Response) { | ||||
|     try{ | ||||
|         const id = Number(req.params.id); | ||||
|  | ||||
|         const [deletedProduct] = await db | ||||
|         .delete(productsTable) | ||||
|         .where(eq(productsTable.id , id)); | ||||
|  | ||||
|         console.log(deleteProduct); | ||||
|     } catch (e) { | ||||
|         res.status(500).send(e); | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										12
									
								
								api/src/type/express/index.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								api/src/type/express/index.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| // to make the file a module and avoid the TypeScript error | ||||
| export {}; | ||||
|  | ||||
| declare global { | ||||
|   namespace Express { | ||||
|     export interface Request { | ||||
|       userId?: Number; | ||||
|       cleanBody?: any; | ||||
|       role: string; | ||||
|     } | ||||
|   } | ||||
| } | ||||
							
								
								
									
										3
									
								
								dashboard/.eslintrc.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								dashboard/.eslintrc.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| { | ||||
|   "extends": ["next/core-web-vitals", "next/typescript"] | ||||
| } | ||||
							
								
								
									
										36
									
								
								dashboard/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								dashboard/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. | ||||
|  | ||||
| # dependencies | ||||
| /node_modules | ||||
| /.pnp | ||||
| .pnp.js | ||||
| .yarn/install-state.gz | ||||
|  | ||||
| # testing | ||||
| /coverage | ||||
|  | ||||
| # next.js | ||||
| /.next/ | ||||
| /out/ | ||||
|  | ||||
| # production | ||||
| /build | ||||
|  | ||||
| # misc | ||||
| .DS_Store | ||||
| *.pem | ||||
|  | ||||
| # debug | ||||
| npm-debug.log* | ||||
| yarn-debug.log* | ||||
| yarn-error.log* | ||||
|  | ||||
| # local env files | ||||
| .env*.local | ||||
|  | ||||
| # vercel | ||||
| .vercel | ||||
|  | ||||
| # typescript | ||||
| *.tsbuildinfo | ||||
| next-env.d.ts | ||||
							
								
								
									
										1
									
								
								dashboard/.npmrc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								dashboard/.npmrc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| legacy-peer-deps=true | ||||
							
								
								
									
										36
									
								
								dashboard/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								dashboard/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). | ||||
|  | ||||
| ## Getting Started | ||||
|  | ||||
| First, run the development server: | ||||
|  | ||||
| ```bash | ||||
| npm run dev | ||||
| # or | ||||
| yarn dev | ||||
| # or | ||||
| pnpm dev | ||||
| # or | ||||
| bun dev | ||||
| ``` | ||||
|  | ||||
| Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. | ||||
|  | ||||
| You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. | ||||
|  | ||||
| This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. | ||||
|  | ||||
| ## Learn More | ||||
|  | ||||
| To learn more about Next.js, take a look at the following resources: | ||||
|  | ||||
| - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. | ||||
| - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. | ||||
|  | ||||
| You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! | ||||
|  | ||||
| ## Deploy on Vercel | ||||
|  | ||||
| The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. | ||||
|  | ||||
| Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. | ||||
							
								
								
									
										
											BIN
										
									
								
								dashboard/app/favicon.ico
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								dashboard/app/favicon.ico
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 25 KiB | 
							
								
								
									
										
											BIN
										
									
								
								dashboard/app/fonts/GeistMonoVF.woff
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								dashboard/app/fonts/GeistMonoVF.woff
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								dashboard/app/fonts/GeistVF.woff
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								dashboard/app/fonts/GeistVF.woff
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										27
									
								
								dashboard/app/globals.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								dashboard/app/globals.css
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| @tailwind base; | ||||
| @tailwind components; | ||||
| @tailwind utilities; | ||||
|  | ||||
| :root { | ||||
|   --background: #ffffff; | ||||
|   --foreground: #171717; | ||||
| } | ||||
|  | ||||
| @media (prefers-color-scheme: dark) { | ||||
|   :root { | ||||
|     --background: #0a0a0a; | ||||
|     --foreground: #ededed; | ||||
|   } | ||||
| } | ||||
|  | ||||
| body { | ||||
|   color: var(--foreground); | ||||
|   background: var(--background); | ||||
|   font-family: Arial, Helvetica, sans-serif; | ||||
| } | ||||
|  | ||||
| @layer utilities { | ||||
|   .text-balance { | ||||
|     text-wrap: balance; | ||||
|   } | ||||
| } | ||||
							
								
								
									
										40
									
								
								dashboard/app/layout.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								dashboard/app/layout.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | ||||
| import type { Metadata } from "next"; | ||||
| import localFont from "next/font/local"; | ||||
| import "./globals.css"; | ||||
|  | ||||
| import '@/app/globals.css'; | ||||
| import { GluestackUIProvider } from '@/components/ui/gluestack-ui-provider'; | ||||
|  | ||||
| const geistSans = localFont({ | ||||
|   src: "./fonts/GeistVF.woff", | ||||
|   variable: "--font-geist-sans", | ||||
|   weight: "100 900", | ||||
| }); | ||||
| const geistMono = localFont({ | ||||
|   src: "./fonts/GeistMonoVF.woff", | ||||
|   variable: "--font-geist-mono", | ||||
|   weight: "100 900", | ||||
| }); | ||||
|  | ||||
| export const metadata: Metadata = { | ||||
|   title: "Create Next App", | ||||
|   description: "Generated by create next app", | ||||
| }; | ||||
|  | ||||
| export default function RootLayout({ | ||||
|   children, | ||||
| }: Readonly<{ | ||||
|   children: React.ReactNode; | ||||
| }>) { | ||||
|   return ( | ||||
|     <html lang="en"> | ||||
|       <body | ||||
|         className={`${geistSans.variable} ${geistMono.variable} antialiased`} | ||||
|       > | ||||
|         <GluestackUIProvider mode="dark"> | ||||
|             {children} | ||||
|           </GluestackUIProvider> | ||||
|         </body> | ||||
|     </html> | ||||
|   ); | ||||
| } | ||||
							
								
								
									
										105
									
								
								dashboard/app/page.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								dashboard/app/page.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,105 @@ | ||||
| import Image from "next/image"; | ||||
| import { Button, ButtonText } from "@/components/ui/button"; | ||||
|  | ||||
| export default function Home() { | ||||
|   return ( | ||||
|     <div className="grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20 font-[family-name:var(--font-geist-sans)]"> | ||||
|       <main className="flex flex-col gap-8 row-start-2 items-center sm:items-start"> | ||||
|         <Button> | ||||
|           <ButtonText>Click me</ButtonText> | ||||
|         </Button> | ||||
|         <Image | ||||
|           className="dark:invert" | ||||
|           src="https://nextjs.org/icons/next.svg" | ||||
|           alt="Next.js logo" | ||||
|           width={180} | ||||
|           height={38} | ||||
|           priority | ||||
|         /> | ||||
|         <ol className="list-inside list-decimal text-sm text-center sm:text-left font-[family-name:var(--font-geist-mono)]"> | ||||
|           <li className="mb-2"> | ||||
|             Get started by editing{" "} | ||||
|             <code className="bg-black/[.05] dark:bg-white/[.06] px-1 py-0.5 rounded font-semibold"> | ||||
|               app/page.tsx | ||||
|             </code> | ||||
|             . | ||||
|           </li> | ||||
|           <li>Save and see your changes instantly.</li> | ||||
|         </ol> | ||||
|  | ||||
|         <div className="flex gap-4 items-center flex-col sm:flex-row"> | ||||
|           <a | ||||
|             className="rounded-full border border-solid border-transparent transition-colors flex items-center justify-center bg-foreground text-background gap-2 hover:bg-[#383838] dark:hover:bg-[#ccc] text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5" | ||||
|             href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app" | ||||
|             target="_blank" | ||||
|             rel="noopener noreferrer" | ||||
|           > | ||||
|             <Image | ||||
|               className="dark:invert" | ||||
|               src="https://nextjs.org/icons/vercel.svg" | ||||
|               alt="Vercel logomark" | ||||
|               width={20} | ||||
|               height={20} | ||||
|             /> | ||||
|             Deploy now | ||||
|           </a> | ||||
|           <a | ||||
|             className="rounded-full border border-solid border-black/[.08] dark:border-white/[.145] transition-colors flex items-center justify-center hover:bg-[#f2f2f2] dark:hover:bg-[#1a1a1a] hover:border-transparent text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 sm:min-w-44" | ||||
|             href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app" | ||||
|             target="_blank" | ||||
|             rel="noopener noreferrer" | ||||
|           > | ||||
|             Read our docs | ||||
|           </a> | ||||
|         </div> | ||||
|       </main> | ||||
|       <footer className="row-start-3 flex gap-6 flex-wrap items-center justify-center"> | ||||
|         <a | ||||
|           className="flex items-center gap-2 hover:underline hover:underline-offset-4" | ||||
|           href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app" | ||||
|           target="_blank" | ||||
|           rel="noopener noreferrer" | ||||
|         > | ||||
|           <Image | ||||
|             aria-hidden | ||||
|             src="https://nextjs.org/icons/file.svg" | ||||
|             alt="File icon" | ||||
|             width={16} | ||||
|             height={16} | ||||
|           /> | ||||
|           Learn | ||||
|         </a> | ||||
|         <a | ||||
|           className="flex items-center gap-2 hover:underline hover:underline-offset-4" | ||||
|           href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app" | ||||
|           target="_blank" | ||||
|           rel="noopener noreferrer" | ||||
|         > | ||||
|           <Image | ||||
|             aria-hidden | ||||
|             src="https://nextjs.org/icons/window.svg" | ||||
|             alt="Window icon" | ||||
|             width={16} | ||||
|             height={16} | ||||
|           /> | ||||
|           Examples | ||||
|         </a> | ||||
|         <a | ||||
|           className="flex items-center gap-2 hover:underline hover:underline-offset-4" | ||||
|           href="https://nextjs.org?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app" | ||||
|           target="_blank" | ||||
|           rel="noopener noreferrer" | ||||
|         > | ||||
|           <Image | ||||
|             aria-hidden | ||||
|             src="https://nextjs.org/icons/globe.svg" | ||||
|             alt="Globe icon" | ||||
|             width={16} | ||||
|             height={16} | ||||
|           /> | ||||
|           Go to nextjs.org → | ||||
|         </a> | ||||
|       </footer> | ||||
|     </div> | ||||
|   ); | ||||
| } | ||||
							
								
								
									
										31
									
								
								dashboard/app/registry.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								dashboard/app/registry.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| 'use client'; | ||||
| import React, { useRef, useState } from 'react'; | ||||
| import { useServerInsertedHTML } from 'next/navigation'; | ||||
| import { StyleRegistry, createStyleRegistry } from 'styled-jsx'; | ||||
| // @ts-expect-error : AppRegistry is defined in react-native-web but its type is not defined | ||||
| import { AppRegistry } from 'react-native-web'; | ||||
| import { flush } from '@gluestack-ui/utils/nativewind-utils'; | ||||
|  | ||||
| export default function StyledJsxRegistry({ | ||||
|   children, | ||||
| }: { | ||||
|   children: React.ReactNode; | ||||
| }) { | ||||
|   // Only create stylesheet once with lazy initial state | ||||
|   // x-ref: https://reactjs.org/docs/hooks-reference.html#lazy-initial-state | ||||
|   const [jsxStyleRegistry] = useState(() => createStyleRegistry()); | ||||
|   const isServerInserted = useRef(false); | ||||
|  | ||||
|   useServerInsertedHTML(() => { | ||||
|     AppRegistry.registerComponent('Main', () => 'main'); | ||||
|     const { getStyleElement } = AppRegistry.getApplication('Main'); | ||||
|     if (!isServerInserted.current) { | ||||
|       isServerInserted.current = true; | ||||
|       const styles = [getStyleElement(), jsxStyleRegistry.styles(), flush()]; | ||||
|       jsxStyleRegistry.flush(); | ||||
|       return <>{styles}</>; | ||||
|     } | ||||
|   }); | ||||
|  | ||||
|   return <StyleRegistry registry={jsxStyleRegistry}>{children}</StyleRegistry>; | ||||
| } | ||||
							
								
								
									
										439
									
								
								dashboard/components/ui/button/index.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										439
									
								
								dashboard/components/ui/button/index.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,439 @@ | ||||
| 'use client'; | ||||
| import React from 'react'; | ||||
| import { createButton } from '@gluestack-ui/core/button/creator'; | ||||
| import { tva } from '@gluestack-ui/utils/nativewind-utils'; | ||||
| import { | ||||
|   withStyleContext, | ||||
|   useStyleContext, | ||||
| } from '@gluestack-ui/utils/nativewind-utils'; | ||||
| import { cssInterop } from 'nativewind'; | ||||
| import { ActivityIndicator, Pressable, Text, View } from 'react-native'; | ||||
| import type { VariantProps } from 'tailwind-variants'; | ||||
| import { PrimitiveIcon, UIIcon } from '@gluestack-ui/core/icon/creator'; | ||||
|  | ||||
| const SCOPE = 'BUTTON'; | ||||
|  | ||||
| const Root = withStyleContext(Pressable, SCOPE); | ||||
|  | ||||
| const UIButton = createButton({ | ||||
|   Root: Root, | ||||
|   Text, | ||||
|   Group: View, | ||||
|   Spinner: ActivityIndicator, | ||||
|   Icon: UIIcon, | ||||
| }); | ||||
|  | ||||
| cssInterop(PrimitiveIcon, { | ||||
|   className: { | ||||
|     target: 'style', | ||||
|     nativeStyleToProp: { | ||||
|       height: true, | ||||
|       width: true, | ||||
|       fill: true, | ||||
|       color: 'classNameColor', | ||||
|       stroke: true, | ||||
|     }, | ||||
|   }, | ||||
| }); | ||||
|  | ||||
| const buttonStyle = tva({ | ||||
|   base: 'group/button rounded bg-primary-500 flex-row items-center justify-center data-[focus-visible=true]:web:outline-none data-[focus-visible=true]:web:ring-2 data-[disabled=true]:opacity-40 gap-2', | ||||
|   variants: { | ||||
|     action: { | ||||
|       primary: | ||||
|         'bg-primary-500 data-[hover=true]:bg-primary-600 data-[active=true]:bg-primary-700 border-primary-300 data-[hover=true]:border-primary-400 data-[active=true]:border-primary-500 data-[focus-visible=true]:web:ring-indicator-info', | ||||
|       secondary: | ||||
|         'bg-secondary-500 border-secondary-300 data-[hover=true]:bg-secondary-600 data-[hover=true]:border-secondary-400 data-[active=true]:bg-secondary-700 data-[active=true]:border-secondary-700 data-[focus-visible=true]:web:ring-indicator-info', | ||||
|       positive: | ||||
|         'bg-success-500 border-success-300 data-[hover=true]:bg-success-600 data-[hover=true]:border-success-400 data-[active=true]:bg-success-700 data-[active=true]:border-success-500 data-[focus-visible=true]:web:ring-indicator-info', | ||||
|       negative: | ||||
|         'bg-error-500 border-error-300 data-[hover=true]:bg-error-600 data-[hover=true]:border-error-400 data-[active=true]:bg-error-700 data-[active=true]:border-error-500 data-[focus-visible=true]:web:ring-indicator-info', | ||||
|       default: | ||||
|         'bg-transparent data-[hover=true]:bg-background-50 data-[active=true]:bg-transparent', | ||||
|     }, | ||||
|     variant: { | ||||
|       link: 'px-0', | ||||
|       outline: | ||||
|         'bg-transparent border data-[hover=true]:bg-background-50 data-[active=true]:bg-transparent', | ||||
|       solid: '', | ||||
|     }, | ||||
|  | ||||
|     size: { | ||||
|       xs: 'px-3.5 h-8', | ||||
|       sm: 'px-4 h-9', | ||||
|       md: 'px-5 h-10', | ||||
|       lg: 'px-6 h-11', | ||||
|       xl: 'px-7 h-12', | ||||
|     }, | ||||
|   }, | ||||
|   compoundVariants: [ | ||||
|     { | ||||
|       action: 'primary', | ||||
|       variant: 'link', | ||||
|       class: | ||||
|         'px-0 bg-transparent data-[hover=true]:bg-transparent data-[active=true]:bg-transparent', | ||||
|     }, | ||||
|     { | ||||
|       action: 'secondary', | ||||
|       variant: 'link', | ||||
|       class: | ||||
|         'px-0 bg-transparent data-[hover=true]:bg-transparent data-[active=true]:bg-transparent', | ||||
|     }, | ||||
|     { | ||||
|       action: 'positive', | ||||
|       variant: 'link', | ||||
|       class: | ||||
|         'px-0 bg-transparent data-[hover=true]:bg-transparent data-[active=true]:bg-transparent', | ||||
|     }, | ||||
|     { | ||||
|       action: 'negative', | ||||
|       variant: 'link', | ||||
|       class: | ||||
|         'px-0 bg-transparent data-[hover=true]:bg-transparent data-[active=true]:bg-transparent', | ||||
|     }, | ||||
|     { | ||||
|       action: 'primary', | ||||
|       variant: 'outline', | ||||
|       class: | ||||
|         'bg-transparent data-[hover=true]:bg-background-50 data-[active=true]:bg-transparent', | ||||
|     }, | ||||
|     { | ||||
|       action: 'secondary', | ||||
|       variant: 'outline', | ||||
|       class: | ||||
|         'bg-transparent data-[hover=true]:bg-background-50 data-[active=true]:bg-transparent', | ||||
|     }, | ||||
|     { | ||||
|       action: 'positive', | ||||
|       variant: 'outline', | ||||
|       class: | ||||
|         'bg-transparent data-[hover=true]:bg-background-50 data-[active=true]:bg-transparent', | ||||
|     }, | ||||
|     { | ||||
|       action: 'negative', | ||||
|       variant: 'outline', | ||||
|       class: | ||||
|         'bg-transparent data-[hover=true]:bg-background-50 data-[active=true]:bg-transparent', | ||||
|     }, | ||||
|   ], | ||||
| }); | ||||
|  | ||||
| const buttonTextStyle = tva({ | ||||
|   base: 'text-typography-0 font-semibold web:select-none', | ||||
|   parentVariants: { | ||||
|     action: { | ||||
|       primary: | ||||
|         'text-primary-600 data-[hover=true]:text-primary-600 data-[active=true]:text-primary-700', | ||||
|       secondary: | ||||
|         'text-typography-500 data-[hover=true]:text-typography-600 data-[active=true]:text-typography-700', | ||||
|       positive: | ||||
|         'text-success-600 data-[hover=true]:text-success-600 data-[active=true]:text-success-700', | ||||
|       negative: | ||||
|         'text-error-600 data-[hover=true]:text-error-600 data-[active=true]:text-error-700', | ||||
|     }, | ||||
|     variant: { | ||||
|       link: 'data-[hover=true]:underline data-[active=true]:underline', | ||||
|       outline: '', | ||||
|       solid: | ||||
|         'text-typography-0 data-[hover=true]:text-typography-0 data-[active=true]:text-typography-0', | ||||
|     }, | ||||
|     size: { | ||||
|       xs: 'text-xs', | ||||
|       sm: 'text-sm', | ||||
|       md: 'text-base', | ||||
|       lg: 'text-lg', | ||||
|       xl: 'text-xl', | ||||
|     }, | ||||
|   }, | ||||
|   parentCompoundVariants: [ | ||||
|     { | ||||
|       variant: 'solid', | ||||
|       action: 'primary', | ||||
|       class: | ||||
|         'text-typography-0 data-[hover=true]:text-typography-0 data-[active=true]:text-typography-0', | ||||
|     }, | ||||
|     { | ||||
|       variant: 'solid', | ||||
|       action: 'secondary', | ||||
|       class: | ||||
|         'text-typography-800 data-[hover=true]:text-typography-800 data-[active=true]:text-typography-800', | ||||
|     }, | ||||
|     { | ||||
|       variant: 'solid', | ||||
|       action: 'positive', | ||||
|       class: | ||||
|         'text-typography-0 data-[hover=true]:text-typography-0 data-[active=true]:text-typography-0', | ||||
|     }, | ||||
|     { | ||||
|       variant: 'solid', | ||||
|       action: 'negative', | ||||
|       class: | ||||
|         'text-typography-0 data-[hover=true]:text-typography-0 data-[active=true]:text-typography-0', | ||||
|     }, | ||||
|     { | ||||
|       variant: 'outline', | ||||
|       action: 'primary', | ||||
|       class: | ||||
|         'text-primary-500 data-[hover=true]:text-primary-500 data-[active=true]:text-primary-500', | ||||
|     }, | ||||
|     { | ||||
|       variant: 'outline', | ||||
|       action: 'secondary', | ||||
|       class: | ||||
|         'text-typography-500 data-[hover=true]:text-primary-600 data-[active=true]:text-typography-700', | ||||
|     }, | ||||
|     { | ||||
|       variant: 'outline', | ||||
|       action: 'positive', | ||||
|       class: | ||||
|         'text-primary-500 data-[hover=true]:text-primary-500 data-[active=true]:text-primary-500', | ||||
|     }, | ||||
|     { | ||||
|       variant: 'outline', | ||||
|       action: 'negative', | ||||
|       class: | ||||
|         'text-primary-500 data-[hover=true]:text-primary-500 data-[active=true]:text-primary-500', | ||||
|     }, | ||||
|   ], | ||||
| }); | ||||
|  | ||||
| const buttonIconStyle = tva({ | ||||
|   base: 'fill-none', | ||||
|   parentVariants: { | ||||
|     variant: { | ||||
|       link: 'data-[hover=true]:underline data-[active=true]:underline', | ||||
|       outline: '', | ||||
|       solid: | ||||
|         'text-typography-0 data-[hover=true]:text-typography-0 data-[active=true]:text-typography-0', | ||||
|     }, | ||||
|     size: { | ||||
|       xs: 'h-3.5 w-3.5', | ||||
|       sm: 'h-4 w-4', | ||||
|       md: 'h-[18px] w-[18px]', | ||||
|       lg: 'h-[18px] w-[18px]', | ||||
|       xl: 'h-5 w-5', | ||||
|     }, | ||||
|     action: { | ||||
|       primary: | ||||
|         'text-primary-600 data-[hover=true]:text-primary-600 data-[active=true]:text-primary-700', | ||||
|       secondary: | ||||
|         'text-typography-500 data-[hover=true]:text-typography-600 data-[active=true]:text-typography-700', | ||||
|       positive: | ||||
|         'text-success-600 data-[hover=true]:text-success-600 data-[active=true]:text-success-700', | ||||
|  | ||||
|       negative: | ||||
|         'text-error-600 data-[hover=true]:text-error-600 data-[active=true]:text-error-700', | ||||
|     }, | ||||
|   }, | ||||
|   parentCompoundVariants: [ | ||||
|     { | ||||
|       variant: 'solid', | ||||
|       action: 'primary', | ||||
|       class: | ||||
|         'text-typography-0 data-[hover=true]:text-typography-0 data-[active=true]:text-typography-0', | ||||
|     }, | ||||
|     { | ||||
|       variant: 'solid', | ||||
|       action: 'secondary', | ||||
|       class: | ||||
|         'text-typography-800 data-[hover=true]:text-typography-800 data-[active=true]:text-typography-800', | ||||
|     }, | ||||
|     { | ||||
|       variant: 'solid', | ||||
|       action: 'positive', | ||||
|       class: | ||||
|         'text-typography-0 data-[hover=true]:text-typography-0 data-[active=true]:text-typography-0', | ||||
|     }, | ||||
|     { | ||||
|       variant: 'solid', | ||||
|       action: 'negative', | ||||
|       class: | ||||
|         'text-typography-0 data-[hover=true]:text-typography-0 data-[active=true]:text-typography-0', | ||||
|     }, | ||||
|   ], | ||||
| }); | ||||
|  | ||||
| const buttonGroupStyle = tva({ | ||||
|   base: '', | ||||
|   variants: { | ||||
|     space: { | ||||
|       'xs': 'gap-1', | ||||
|       'sm': 'gap-2', | ||||
|       'md': 'gap-3', | ||||
|       'lg': 'gap-4', | ||||
|       'xl': 'gap-5', | ||||
|       '2xl': 'gap-6', | ||||
|       '3xl': 'gap-7', | ||||
|       '4xl': 'gap-8', | ||||
|     }, | ||||
|     isAttached: { | ||||
|       true: 'gap-0', | ||||
|     }, | ||||
|     flexDirection: { | ||||
|       'row': 'flex-row', | ||||
|       'column': 'flex-col', | ||||
|       'row-reverse': 'flex-row-reverse', | ||||
|       'column-reverse': 'flex-col-reverse', | ||||
|     }, | ||||
|   }, | ||||
| }); | ||||
|  | ||||
| type IButtonProps = Omit< | ||||
|   React.ComponentPropsWithoutRef<typeof UIButton>, | ||||
|   'context' | ||||
| > & | ||||
|   VariantProps<typeof buttonStyle> & { className?: string }; | ||||
|  | ||||
| const Button = React.forwardRef< | ||||
|   React.ElementRef<typeof UIButton>, | ||||
|   IButtonProps | ||||
| >( | ||||
|   ( | ||||
|     { className, variant = 'solid', size = 'md', action = 'primary', ...props }, | ||||
|     ref | ||||
|   ) => { | ||||
|     return ( | ||||
|       <UIButton | ||||
|         ref={ref} | ||||
|         {...props} | ||||
|         className={buttonStyle({ variant, size, action, class: className })} | ||||
|         context={{ variant, size, action }} | ||||
|       /> | ||||
|     ); | ||||
|   } | ||||
| ); | ||||
|  | ||||
| type IButtonTextProps = React.ComponentPropsWithoutRef<typeof UIButton.Text> & | ||||
|   VariantProps<typeof buttonTextStyle> & { className?: string }; | ||||
|  | ||||
| const ButtonText = React.forwardRef< | ||||
|   React.ElementRef<typeof UIButton.Text>, | ||||
|   IButtonTextProps | ||||
| >(({ className, variant, size, action, ...props }, ref) => { | ||||
|   const { | ||||
|     variant: parentVariant, | ||||
|     size: parentSize, | ||||
|     action: parentAction, | ||||
|   } = useStyleContext(SCOPE); | ||||
|  | ||||
|   return ( | ||||
|     <UIButton.Text | ||||
|       ref={ref} | ||||
|       {...props} | ||||
|       className={buttonTextStyle({ | ||||
|         parentVariants: { | ||||
|           variant: parentVariant, | ||||
|           size: parentSize, | ||||
|           action: parentAction, | ||||
|         }, | ||||
|         variant: variant as 'link' | 'outline' | 'solid' | undefined, | ||||
|         size, | ||||
|         action: action as | ||||
|           | 'primary' | ||||
|           | 'secondary' | ||||
|           | 'positive' | ||||
|           | 'negative' | ||||
|           | undefined, | ||||
|         class: className, | ||||
|       })} | ||||
|     /> | ||||
|   ); | ||||
| }); | ||||
|  | ||||
| const ButtonSpinner = UIButton.Spinner; | ||||
|  | ||||
| type IButtonIcon = React.ComponentPropsWithoutRef<typeof UIButton.Icon> & | ||||
|   VariantProps<typeof buttonIconStyle> & { | ||||
|     className?: string | undefined; | ||||
|     as?: React.ElementType; | ||||
|     height?: number; | ||||
|     width?: number; | ||||
|   }; | ||||
|  | ||||
| const ButtonIcon = React.forwardRef< | ||||
|   React.ElementRef<typeof UIButton.Icon>, | ||||
|   IButtonIcon | ||||
| >(({ className, size, ...props }, ref) => { | ||||
|   const { | ||||
|     variant: parentVariant, | ||||
|     size: parentSize, | ||||
|     action: parentAction, | ||||
|   } = useStyleContext(SCOPE); | ||||
|  | ||||
|   if (typeof size === 'number') { | ||||
|     return ( | ||||
|       <UIButton.Icon | ||||
|         ref={ref} | ||||
|         {...props} | ||||
|         className={buttonIconStyle({ class: className })} | ||||
|         size={size} | ||||
|       /> | ||||
|     ); | ||||
|   } else if ( | ||||
|     (props.height !== undefined || props.width !== undefined) && | ||||
|     size === undefined | ||||
|   ) { | ||||
|     return ( | ||||
|       <UIButton.Icon | ||||
|         ref={ref} | ||||
|         {...props} | ||||
|         className={buttonIconStyle({ class: className })} | ||||
|       /> | ||||
|     ); | ||||
|   } | ||||
|   return ( | ||||
|     <UIButton.Icon | ||||
|       {...props} | ||||
|       className={buttonIconStyle({ | ||||
|         parentVariants: { | ||||
|           size: parentSize, | ||||
|           variant: parentVariant, | ||||
|           action: parentAction, | ||||
|         }, | ||||
|         size, | ||||
|         class: className, | ||||
|       })} | ||||
|       ref={ref} | ||||
|     /> | ||||
|   ); | ||||
| }); | ||||
|  | ||||
| type IButtonGroupProps = React.ComponentPropsWithoutRef<typeof UIButton.Group> & | ||||
|   VariantProps<typeof buttonGroupStyle>; | ||||
|  | ||||
| const ButtonGroup = React.forwardRef< | ||||
|   React.ElementRef<typeof UIButton.Group>, | ||||
|   IButtonGroupProps | ||||
| >( | ||||
|   ( | ||||
|     { | ||||
|       className, | ||||
|       space = 'md', | ||||
|       isAttached = false, | ||||
|       flexDirection = 'column', | ||||
|       ...props | ||||
|     }, | ||||
|     ref | ||||
|   ) => { | ||||
|     return ( | ||||
|       <UIButton.Group | ||||
|         className={buttonGroupStyle({ | ||||
|           class: className, | ||||
|           space, | ||||
|           isAttached: isAttached as boolean, | ||||
|           flexDirection: flexDirection as any, | ||||
|         })} | ||||
|         {...props} | ||||
|         ref={ref} | ||||
|       /> | ||||
|     ); | ||||
|   } | ||||
| ); | ||||
|  | ||||
| Button.displayName = 'Button'; | ||||
| ButtonText.displayName = 'ButtonText'; | ||||
| ButtonSpinner.displayName = 'ButtonSpinner'; | ||||
| ButtonIcon.displayName = 'ButtonIcon'; | ||||
| ButtonGroup.displayName = 'ButtonGroup'; | ||||
|  | ||||
| export { Button, ButtonText, ButtonSpinner, ButtonIcon, ButtonGroup }; | ||||
							
								
								
									
										309
									
								
								dashboard/components/ui/gluestack-ui-provider/config.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										309
									
								
								dashboard/components/ui/gluestack-ui-provider/config.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,309 @@ | ||||
| 'use client'; | ||||
| import { vars } from 'nativewind'; | ||||
|  | ||||
| export const config = { | ||||
|   light: vars({ | ||||
|     '--color-primary-0': '179 179 179', | ||||
|     '--color-primary-50': '153 153 153', | ||||
|     '--color-primary-100': '128 128 128', | ||||
|     '--color-primary-200': '115 115 115', | ||||
|     '--color-primary-300': '102 102 102', | ||||
|     '--color-primary-400': '82 82 82', | ||||
|     '--color-primary-500': '51 51 51', | ||||
|     '--color-primary-600': '41 41 41', | ||||
|     '--color-primary-700': '31 31 31', | ||||
|     '--color-primary-800': '13 13 13', | ||||
|     '--color-primary-900': '10 10 10', | ||||
|     '--color-primary-950': '8 8 8', | ||||
|  | ||||
|     /* Secondary  */ | ||||
|     '--color-secondary-0': '253 253 253', | ||||
|     '--color-secondary-50': '251 251 251', | ||||
|     '--color-secondary-100': '246 246 246', | ||||
|     '--color-secondary-200': '242 242 242', | ||||
|     '--color-secondary-300': '237 237 237', | ||||
|     '--color-secondary-400': '230 230 231', | ||||
|     '--color-secondary-500': '217 217 219', | ||||
|     '--color-secondary-600': '198 199 199', | ||||
|     '--color-secondary-700': '189 189 189', | ||||
|     '--color-secondary-800': '177 177 177', | ||||
|     '--color-secondary-900': '165 164 164', | ||||
|     '--color-secondary-950': '157 157 157', | ||||
|  | ||||
|     /* Tertiary */ | ||||
|     '--color-tertiary-0': '255 250 245', | ||||
|     '--color-tertiary-50': '255 242 229', | ||||
|     '--color-tertiary-100': '255 233 213', | ||||
|     '--color-tertiary-200': '254 209 170', | ||||
|     '--color-tertiary-300': '253 180 116', | ||||
|     '--color-tertiary-400': '251 157 75', | ||||
|     '--color-tertiary-500': '231 129 40', | ||||
|     '--color-tertiary-600': '215 117 31', | ||||
|     '--color-tertiary-700': '180 98 26', | ||||
|     '--color-tertiary-800': '130 73 23', | ||||
|     '--color-tertiary-900': '108 61 19', | ||||
|     '--color-tertiary-950': '84 49 18', | ||||
|  | ||||
|     /* Error */ | ||||
|     '--color-error-0': '254 233 233', | ||||
|     '--color-error-50': '254 226 226', | ||||
|     '--color-error-100': '254 202 202', | ||||
|     '--color-error-200': '252 165 165', | ||||
|     '--color-error-300': '248 113 113', | ||||
|     '--color-error-400': '239 68 68', | ||||
|     '--color-error-500': '230 53 53', | ||||
|     '--color-error-600': '220 38 38', | ||||
|     '--color-error-700': '185 28 28', | ||||
|     '--color-error-800': '153 27 27', | ||||
|     '--color-error-900': '127 29 29', | ||||
|     '--color-error-950': '83 19 19', | ||||
|  | ||||
|     /* Success */ | ||||
|     '--color-success-0': '228 255 244', | ||||
|     '--color-success-50': '202 255 232', | ||||
|     '--color-success-100': '162 241 192', | ||||
|     '--color-success-200': '132 211 162', | ||||
|     '--color-success-300': '102 181 132', | ||||
|     '--color-success-400': '72 151 102', | ||||
|     '--color-success-500': '52 131 82', | ||||
|     '--color-success-600': '42 121 72', | ||||
|     '--color-success-700': '32 111 62', | ||||
|     '--color-success-800': '22 101 52', | ||||
|     '--color-success-900': '20 83 45', | ||||
|     '--color-success-950': '27 50 36', | ||||
|  | ||||
|     /* Warning */ | ||||
|     '--color-warning-0': '255 249 245', | ||||
|     '--color-warning-50': '255 244 236', | ||||
|     '--color-warning-100': '255 231 213', | ||||
|     '--color-warning-200': '254 205 170', | ||||
|     '--color-warning-300': '253 173 116', | ||||
|     '--color-warning-400': '251 149 75', | ||||
|     '--color-warning-500': '231 120 40', | ||||
|     '--color-warning-600': '215 108 31', | ||||
|     '--color-warning-700': '180 90 26', | ||||
|     '--color-warning-800': '130 68 23', | ||||
|     '--color-warning-900': '108 56 19', | ||||
|     '--color-warning-950': '84 45 18', | ||||
|  | ||||
|     /* Info */ | ||||
|     '--color-info-0': '236 248 254', | ||||
|     '--color-info-50': '199 235 252', | ||||
|     '--color-info-100': '162 221 250', | ||||
|     '--color-info-200': '124 207 248', | ||||
|     '--color-info-300': '87 194 246', | ||||
|     '--color-info-400': '50 180 244', | ||||
|     '--color-info-500': '13 166 242', | ||||
|     '--color-info-600': '11 141 205', | ||||
|     '--color-info-700': '9 115 168', | ||||
|     '--color-info-800': '7 90 131', | ||||
|     '--color-info-900': '5 64 93', | ||||
|     '--color-info-950': '3 38 56', | ||||
|  | ||||
|     /* Typography */ | ||||
|     '--color-typography-0': '254 254 255', | ||||
|     '--color-typography-50': '245 245 245', | ||||
|     '--color-typography-100': '229 229 229', | ||||
|     '--color-typography-200': '219 219 220', | ||||
|     '--color-typography-300': '212 212 212', | ||||
|     '--color-typography-400': '163 163 163', | ||||
|     '--color-typography-500': '140 140 140', | ||||
|     '--color-typography-600': '115 115 115', | ||||
|     '--color-typography-700': '82 82 82', | ||||
|     '--color-typography-800': '64 64 64', | ||||
|     '--color-typography-900': '38 38 39', | ||||
|     '--color-typography-950': '23 23 23', | ||||
|  | ||||
|     /* Outline */ | ||||
|     '--color-outline-0': '253 254 254', | ||||
|     '--color-outline-50': '243 243 243', | ||||
|     '--color-outline-100': '230 230 230', | ||||
|     '--color-outline-200': '221 220 219', | ||||
|     '--color-outline-300': '211 211 211', | ||||
|     '--color-outline-400': '165 163 163', | ||||
|     '--color-outline-500': '140 141 141', | ||||
|     '--color-outline-600': '115 116 116', | ||||
|     '--color-outline-700': '83 82 82', | ||||
|     '--color-outline-800': '65 65 65', | ||||
|     '--color-outline-900': '39 38 36', | ||||
|     '--color-outline-950': '26 23 23', | ||||
|  | ||||
|     /* Background */ | ||||
|     '--color-background-0': '255 255 255', | ||||
|     '--color-background-50': '246 246 246', | ||||
|     '--color-background-100': '242 241 241', | ||||
|     '--color-background-200': '220 219 219', | ||||
|     '--color-background-300': '213 212 212', | ||||
|     '--color-background-400': '162 163 163', | ||||
|     '--color-background-500': '142 142 142', | ||||
|     '--color-background-600': '116 116 116', | ||||
|     '--color-background-700': '83 82 82', | ||||
|     '--color-background-800': '65 64 64', | ||||
|     '--color-background-900': '39 38 37', | ||||
|     '--color-background-950': '18 18 18', | ||||
|  | ||||
|     /* Background Special */ | ||||
|     '--color-background-error': '254 241 241', | ||||
|     '--color-background-warning': '255 243 234', | ||||
|     '--color-background-success': '237 252 242', | ||||
|     '--color-background-muted': '247 248 247', | ||||
|     '--color-background-info': '235 248 254', | ||||
|  | ||||
|     /* Focus Ring Indicator  */ | ||||
|     '--color-indicator-primary': '55 55 55', | ||||
|     '--color-indicator-info': '83 153 236', | ||||
|     '--color-indicator-error': '185 28 28', | ||||
|   }), | ||||
|   dark: vars({ | ||||
|     '--color-primary-0': '166 166 166', | ||||
|     '--color-primary-50': '175 175 175', | ||||
|     '--color-primary-100': '186 186 186', | ||||
|     '--color-primary-200': '197 197 197', | ||||
|     '--color-primary-300': '212 212 212', | ||||
|     '--color-primary-400': '221 221 221', | ||||
|     '--color-primary-500': '230 230 230', | ||||
|     '--color-primary-600': '240 240 240', | ||||
|     '--color-primary-700': '250 250 250', | ||||
|     '--color-primary-800': '253 253 253', | ||||
|     '--color-primary-900': '254 249 249', | ||||
|     '--color-primary-950': '253 252 252', | ||||
|  | ||||
|     /* Secondary  */ | ||||
|     '--color-secondary-0': '20 20 20', | ||||
|     '--color-secondary-50': '23 23 23', | ||||
|     '--color-secondary-100': '31 31 31', | ||||
|     '--color-secondary-200': '39 39 39', | ||||
|     '--color-secondary-300': '44 44 44', | ||||
|     '--color-secondary-400': '56 57 57', | ||||
|     '--color-secondary-500': '63 64 64', | ||||
|     '--color-secondary-600': '86 86 86', | ||||
|     '--color-secondary-700': '110 110 110', | ||||
|     '--color-secondary-800': '135 135 135', | ||||
|     '--color-secondary-900': '150 150 150', | ||||
|     '--color-secondary-950': '164 164 164', | ||||
|  | ||||
|     /* Tertiary */ | ||||
|     '--color-tertiary-0': '84 49 18', | ||||
|     '--color-tertiary-50': '108 61 19', | ||||
|     '--color-tertiary-100': '130 73 23', | ||||
|     '--color-tertiary-200': '180 98 26', | ||||
|     '--color-tertiary-300': '215 117 31', | ||||
|     '--color-tertiary-400': '231 129 40', | ||||
|     '--color-tertiary-500': '251 157 75', | ||||
|     '--color-tertiary-600': '253 180 116', | ||||
|     '--color-tertiary-700': '254 209 170', | ||||
|     '--color-tertiary-800': '255 233 213', | ||||
|     '--color-tertiary-900': '255 242 229', | ||||
|     '--color-tertiary-950': '255 250 245', | ||||
|  | ||||
|     /* Error */ | ||||
|     '--color-error-0': '83 19 19', | ||||
|     '--color-error-50': '127 29 29', | ||||
|     '--color-error-100': '153 27 27', | ||||
|     '--color-error-200': '185 28 28', | ||||
|     '--color-error-300': '220 38 38', | ||||
|     '--color-error-400': '230 53 53', | ||||
|     '--color-error-500': '239 68 68', | ||||
|     '--color-error-600': '249 97 96', | ||||
|     '--color-error-700': '229 91 90', | ||||
|     '--color-error-800': '254 202 202', | ||||
|     '--color-error-900': '254 226 226', | ||||
|     '--color-error-950': '254 233 233', | ||||
|  | ||||
|     /* Success */ | ||||
|     '--color-success-0': '27 50 36', | ||||
|     '--color-success-50': '20 83 45', | ||||
|     '--color-success-100': '22 101 52', | ||||
|     '--color-success-200': '32 111 62', | ||||
|     '--color-success-300': '42 121 72', | ||||
|     '--color-success-400': '52 131 82', | ||||
|     '--color-success-500': '72 151 102', | ||||
|     '--color-success-600': '102 181 132', | ||||
|     '--color-success-700': '132 211 162', | ||||
|     '--color-success-800': '162 241 192', | ||||
|     '--color-success-900': '202 255 232', | ||||
|     '--color-success-950': '228 255 244', | ||||
|  | ||||
|     /* Warning */ | ||||
|     '--color-warning-0': '84 45 18', | ||||
|     '--color-warning-50': '108 56 19', | ||||
|     '--color-warning-100': '130 68 23', | ||||
|     '--color-warning-200': '180 90 26', | ||||
|     '--color-warning-300': '215 108 31', | ||||
|     '--color-warning-400': '231 120 40', | ||||
|     '--color-warning-500': '251 149 75', | ||||
|     '--color-warning-600': '253 173 116', | ||||
|     '--color-warning-700': '254 205 170', | ||||
|     '--color-warning-800': '255 231 213', | ||||
|     '--color-warning-900': '255 244 237', | ||||
|     '--color-warning-950': '255 249 245', | ||||
|  | ||||
|     /* Info */ | ||||
|     '--color-info-0': '3 38 56', | ||||
|     '--color-info-50': '5 64 93', | ||||
|     '--color-info-100': '7 90 131', | ||||
|     '--color-info-200': '9 115 168', | ||||
|     '--color-info-300': '11 141 205', | ||||
|     '--color-info-400': '13 166 242', | ||||
|     '--color-info-500': '50 180 244', | ||||
|     '--color-info-600': '87 194 246', | ||||
|     '--color-info-700': '124 207 248', | ||||
|     '--color-info-800': '162 221 250', | ||||
|     '--color-info-900': '199 235 252', | ||||
|     '--color-info-950': '236 248 254', | ||||
|  | ||||
|     /* Typography */ | ||||
|     '--color-typography-0': '23 23 23', | ||||
|     '--color-typography-50': '38 38 39', | ||||
|     '--color-typography-100': '64 64 64', | ||||
|     '--color-typography-200': '82 82 82', | ||||
|     '--color-typography-300': '115 115 115', | ||||
|     '--color-typography-400': '140 140 140', | ||||
|     '--color-typography-500': '163 163 163', | ||||
|     '--color-typography-600': '212 212 212', | ||||
|     '--color-typography-700': '219 219 220', | ||||
|     '--color-typography-800': '229 229 229', | ||||
|     '--color-typography-900': '245 245 245', | ||||
|     '--color-typography-950': '254 254 255', | ||||
|  | ||||
|     /* Outline */ | ||||
|     '--color-outline-0': '26 23 23', | ||||
|     '--color-outline-50': '39 38 36', | ||||
|     '--color-outline-100': '65 65 65', | ||||
|     '--color-outline-200': '83 82 82', | ||||
|     '--color-outline-300': '115 116 116', | ||||
|     '--color-outline-400': '140 141 141', | ||||
|     '--color-outline-500': '165 163 163', | ||||
|     '--color-outline-600': '211 211 211', | ||||
|     '--color-outline-700': '221 220 219', | ||||
|     '--color-outline-800': '230 230 230', | ||||
|     '--color-outline-900': '243 243 243', | ||||
|     '--color-outline-950': '253 254 254', | ||||
|  | ||||
|     /* Background */ | ||||
|     '--color-background-0': '18 18 18', | ||||
|     '--color-background-50': '39 38 37', | ||||
|     '--color-background-100': '65 64 64', | ||||
|     '--color-background-200': '83 82 82', | ||||
|     '--color-background-300': '116 116 116', | ||||
|     '--color-background-400': '142 142 142', | ||||
|     '--color-background-500': '162 163 163', | ||||
|     '--color-background-600': '213 212 212', | ||||
|     '--color-background-700': '229 228 228', | ||||
|     '--color-background-800': '242 241 241', | ||||
|     '--color-background-900': '246 246 246', | ||||
|     '--color-background-950': '255 255 255', | ||||
|  | ||||
|     /* Background Special */ | ||||
|     '--color-background-error': '66 43 43', | ||||
|     '--color-background-warning': '65 47 35', | ||||
|     '--color-background-success': '28 43 33', | ||||
|     '--color-background-muted': '51 51 51', | ||||
|     '--color-background-info': '26 40 46', | ||||
|  | ||||
|     /* Focus Ring Indicator  */ | ||||
|     '--color-indicator-primary': '247 247 247', | ||||
|     '--color-indicator-info': '161 199 245', | ||||
|     '--color-indicator-error': '232 70 69', | ||||
|   }), | ||||
| }; | ||||
| @@ -0,0 +1,87 @@ | ||||
| // This is a Next.js 15 compatible version of the GluestackUIProvider | ||||
| 'use client'; | ||||
| import React, { useEffect, useLayoutEffect } from 'react'; | ||||
| import { config } from './config'; | ||||
| import { OverlayProvider } from '@gluestack-ui/core/overlay/creator'; | ||||
| import { ToastProvider } from '@gluestack-ui/core/toast/creator'; | ||||
| import { setFlushStyles } from '@gluestack-ui/utils/nativewind-utils'; | ||||
| import { script } from './script'; | ||||
|  | ||||
| const variableStyleTagId = 'nativewind-style'; | ||||
| const createStyle = (styleTagId: string) => { | ||||
|   const style = document.createElement('style'); | ||||
|   style.id = styleTagId; | ||||
|   style.appendChild(document.createTextNode('')); | ||||
|   return style; | ||||
| }; | ||||
|  | ||||
| export const useSafeLayoutEffect = | ||||
|   typeof window !== 'undefined' ? useLayoutEffect : useEffect; | ||||
|  | ||||
| export function GluestackUIProvider({ | ||||
|   mode = 'light', | ||||
|   ...props | ||||
| }: { | ||||
|   mode?: 'light' | 'dark' | 'system'; | ||||
|   children?: React.ReactNode; | ||||
| }) { | ||||
|   let cssVariablesWithMode = ``; | ||||
|   Object.keys(config).forEach((configKey) => { | ||||
|     cssVariablesWithMode += | ||||
|       configKey === 'dark' ? `\n .dark {\n ` : `\n:root {\n`; | ||||
|     const cssVariables = Object.keys( | ||||
|       config[configKey as keyof typeof config] | ||||
|     ).reduce((acc: string, curr: string) => { | ||||
|       acc += `${curr}:${config[configKey as keyof typeof config][curr]}; `; | ||||
|       return acc; | ||||
|     }, ''); | ||||
|     cssVariablesWithMode += `${cssVariables} \n}`; | ||||
|   }); | ||||
|  | ||||
|   setFlushStyles(cssVariablesWithMode); | ||||
|  | ||||
|   const handleMediaQuery = React.useCallback((e: MediaQueryListEvent) => { | ||||
|     script(e.matches ? 'dark' : 'light'); | ||||
|   }, []); | ||||
|  | ||||
|   useSafeLayoutEffect(() => { | ||||
|     if (mode !== 'system') { | ||||
|       const documentElement = document.documentElement; | ||||
|       if (documentElement) { | ||||
|         documentElement.classList.add(mode); | ||||
|         documentElement.classList.remove(mode === 'light' ? 'dark' : 'light'); | ||||
|         documentElement.style.colorScheme = mode; | ||||
|       } | ||||
|     } | ||||
|   }, [mode]); | ||||
|  | ||||
|   useSafeLayoutEffect(() => { | ||||
|     if (mode !== 'system') return; | ||||
|     const media = window.matchMedia('(prefers-color-scheme: dark)'); | ||||
|  | ||||
|     media.addListener(handleMediaQuery); | ||||
|  | ||||
|     return () => media.removeListener(handleMediaQuery); | ||||
|   }, [handleMediaQuery]); | ||||
|  | ||||
|   useSafeLayoutEffect(() => { | ||||
|     if (typeof window !== 'undefined') { | ||||
|       const documentElement = document.documentElement; | ||||
|       if (documentElement) { | ||||
|         const head = documentElement.querySelector('head'); | ||||
|         let style = head?.querySelector(`[id='${variableStyleTagId}']`); | ||||
|         if (!style) { | ||||
|           style = createStyle(variableStyleTagId); | ||||
|           style.innerHTML = cssVariablesWithMode; | ||||
|           if (head) head.appendChild(style); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   }, []); | ||||
|  | ||||
|   return ( | ||||
|     <OverlayProvider> | ||||
|       <ToastProvider>{props.children}</ToastProvider> | ||||
|     </OverlayProvider> | ||||
|   ); | ||||
| } | ||||
							
								
								
									
										38
									
								
								dashboard/components/ui/gluestack-ui-provider/index.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								dashboard/components/ui/gluestack-ui-provider/index.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| import React, { useEffect } from 'react'; | ||||
| import { config } from './config'; | ||||
| import { View, ViewProps } from 'react-native'; | ||||
| import { OverlayProvider } from '@gluestack-ui/core/overlay/creator'; | ||||
| import { ToastProvider } from '@gluestack-ui/core/toast/creator'; | ||||
| import { useColorScheme } from 'nativewind'; | ||||
|  | ||||
| export type ModeType = 'light' | 'dark' | 'system'; | ||||
|  | ||||
| export function GluestackUIProvider({ | ||||
|   mode = 'light', | ||||
|   ...props | ||||
| }: { | ||||
|   mode?: ModeType; | ||||
|   children?: React.ReactNode; | ||||
|   style?: ViewProps['style']; | ||||
| }) { | ||||
|   const { colorScheme, setColorScheme } = useColorScheme(); | ||||
|  | ||||
|   useEffect(() => { | ||||
|     setColorScheme(mode); | ||||
|     // eslint-disable-next-line react-hooks/exhaustive-deps | ||||
|   }, [mode]); | ||||
|  | ||||
|   return ( | ||||
|     <View | ||||
|       style={[ | ||||
|         config[colorScheme!], | ||||
|         { flex: 1, height: '100%', width: '100%' }, | ||||
|         props.style, | ||||
|       ]} | ||||
|     > | ||||
|       <OverlayProvider> | ||||
|         <ToastProvider>{props.children}</ToastProvider> | ||||
|       </OverlayProvider> | ||||
|     </View> | ||||
|   ); | ||||
| } | ||||
							
								
								
									
										96
									
								
								dashboard/components/ui/gluestack-ui-provider/index.web.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								dashboard/components/ui/gluestack-ui-provider/index.web.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,96 @@ | ||||
| 'use client'; | ||||
| import React, { useEffect, useLayoutEffect } from 'react'; | ||||
| import { config } from './config'; | ||||
| import { OverlayProvider } from '@gluestack-ui/core/overlay/creator'; | ||||
| import { ToastProvider } from '@gluestack-ui/core/toast/creator'; | ||||
| import { setFlushStyles } from '@gluestack-ui/utils/nativewind-utils'; | ||||
| import { script } from './script'; | ||||
|  | ||||
| export type ModeType = 'light' | 'dark' | 'system'; | ||||
|  | ||||
| const variableStyleTagId = 'nativewind-style'; | ||||
| const createStyle = (styleTagId: string) => { | ||||
|   const style = document.createElement('style'); | ||||
|   style.id = styleTagId; | ||||
|   style.appendChild(document.createTextNode('')); | ||||
|   return style; | ||||
| }; | ||||
|  | ||||
| export const useSafeLayoutEffect = | ||||
|   typeof window !== 'undefined' ? useLayoutEffect : useEffect; | ||||
|  | ||||
| export function GluestackUIProvider({ | ||||
|   mode = 'light', | ||||
|   ...props | ||||
| }: { | ||||
|   mode?: ModeType; | ||||
|   children?: React.ReactNode; | ||||
| }) { | ||||
|   let cssVariablesWithMode = ``; | ||||
|   Object.keys(config).forEach((configKey) => { | ||||
|     cssVariablesWithMode += | ||||
|       configKey === 'dark' ? `\n .dark {\n ` : `\n:root {\n`; | ||||
|     const cssVariables = Object.keys( | ||||
|       config[configKey as keyof typeof config] | ||||
|     ).reduce((acc: string, curr: string) => { | ||||
|       acc += `${curr}:${config[configKey as keyof typeof config][curr]}; `; | ||||
|       return acc; | ||||
|     }, ''); | ||||
|     cssVariablesWithMode += `${cssVariables} \n}`; | ||||
|   }); | ||||
|  | ||||
|   setFlushStyles(cssVariablesWithMode); | ||||
|  | ||||
|   const handleMediaQuery = React.useCallback((e: MediaQueryListEvent) => { | ||||
|     script(e.matches ? 'dark' : 'light'); | ||||
|   }, []); | ||||
|  | ||||
|   useSafeLayoutEffect(() => { | ||||
|     if (mode !== 'system') { | ||||
|       const documentElement = document.documentElement; | ||||
|       if (documentElement) { | ||||
|         documentElement.classList.add(mode); | ||||
|         documentElement.classList.remove(mode === 'light' ? 'dark' : 'light'); | ||||
|         documentElement.style.colorScheme = mode; | ||||
|       } | ||||
|     } | ||||
|   }, [mode]); | ||||
|  | ||||
|   useSafeLayoutEffect(() => { | ||||
|     if (mode !== 'system') return; | ||||
|     const media = window.matchMedia('(prefers-color-scheme: dark)'); | ||||
|  | ||||
|     media.addListener(handleMediaQuery); | ||||
|  | ||||
|     return () => media.removeListener(handleMediaQuery); | ||||
|   }, [handleMediaQuery]); | ||||
|  | ||||
|   useSafeLayoutEffect(() => { | ||||
|     if (typeof window !== 'undefined') { | ||||
|       const documentElement = document.documentElement; | ||||
|       if (documentElement) { | ||||
|         const head = documentElement.querySelector('head'); | ||||
|         let style = head?.querySelector(`[id='${variableStyleTagId}']`); | ||||
|         if (!style) { | ||||
|           style = createStyle(variableStyleTagId); | ||||
|           style.innerHTML = cssVariablesWithMode; | ||||
|           if (head) head.appendChild(style); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   }, []); | ||||
|  | ||||
|   return ( | ||||
|     <> | ||||
|       <script | ||||
|         suppressHydrationWarning | ||||
|         dangerouslySetInnerHTML={{ | ||||
|           __html: `(${script.toString()})('${mode}')`, | ||||
|         }} | ||||
|       /> | ||||
|       <OverlayProvider> | ||||
|         <ToastProvider>{props.children}</ToastProvider> | ||||
|       </OverlayProvider> | ||||
|     </> | ||||
|   ); | ||||
| } | ||||
							
								
								
									
										19
									
								
								dashboard/components/ui/gluestack-ui-provider/script.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								dashboard/components/ui/gluestack-ui-provider/script.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| export const script = (mode: string) => { | ||||
|   const documentElement = document.documentElement; | ||||
|  | ||||
|   function getSystemColorMode() { | ||||
|     return window.matchMedia('(prefers-color-scheme: dark)').matches | ||||
|       ? 'dark' | ||||
|       : 'light'; | ||||
|   } | ||||
|  | ||||
|   try { | ||||
|     const isSystem = mode === 'system'; | ||||
|     const theme = isSystem ? getSystemColorMode() : mode; | ||||
|     documentElement.classList.remove(theme === 'light' ? 'dark' : 'light'); | ||||
|     documentElement.classList.add(theme); | ||||
|     documentElement.style.colorScheme = theme; | ||||
|   } catch (e) { | ||||
|     console.error(e); | ||||
|   } | ||||
| }; | ||||
							
								
								
									
										1
									
								
								dashboard/nativewind-env.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								dashboard/nativewind-env.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| /// <reference types="nativewind/types" /> | ||||
							
								
								
									
										35
									
								
								dashboard/next.config.mjs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								dashboard/next.config.mjs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| import { withGluestackUI } from '@gluestack/ui-next-adapter'; | ||||
|  | ||||
| /** @type {import('next').NextConfig} */ | ||||
| const nextConfig = { | ||||
|   eslint: { | ||||
|     ignoreDuringBuilds: true, | ||||
|   }, | ||||
|   typescript: { | ||||
|     ignoreBuildErrors: true, | ||||
|   }, | ||||
|   transpilePackages: [], | ||||
|   experimental: { | ||||
|     // Enable experimental features if needed | ||||
|   }, | ||||
| }; | ||||
|  | ||||
| // Apply gluestack adapter | ||||
| const gluestackConfig = withGluestackUI(nextConfig); | ||||
|  | ||||
| // Remove invalid compiler options that gluestack might add | ||||
| if (gluestackConfig.compiler && gluestackConfig.compiler.define) { | ||||
|   delete gluestackConfig.compiler.define; | ||||
| } | ||||
|  | ||||
| // Remove invalid turbopack option | ||||
| if (gluestackConfig.turbopack) { | ||||
|   delete gluestackConfig.turbopack; | ||||
| } | ||||
|  | ||||
| // Remove any other invalid options that might cause warnings | ||||
| if (gluestackConfig.compiler && Object.keys(gluestackConfig.compiler).length === 0) { | ||||
|   delete gluestackConfig.compiler; | ||||
| } | ||||
|  | ||||
| export default gluestackConfig; | ||||
							
								
								
									
										9708
									
								
								dashboard/package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										9708
									
								
								dashboard/package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										44
									
								
								dashboard/package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								dashboard/package.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | ||||
| { | ||||
|   "name": "dashboard", | ||||
|   "version": "0.1.0", | ||||
|   "private": true, | ||||
|   "scripts": { | ||||
|     "dev": "next dev", | ||||
|     "build": "next build", | ||||
|     "start": "next start", | ||||
|     "lint": "next lint" | ||||
|   }, | ||||
|   "dependencies": { | ||||
|     "@expo/html-elements": "^0.10.1", | ||||
|     "@gluestack-ui/core": "^3.0.10", | ||||
|     "@gluestack-ui/utils": "^3.0.7", | ||||
|     "@gluestack/ui-next-adapter": "^3.0.3", | ||||
|     "@legendapp/motion": "^2.3.0", | ||||
|     "dom-helpers": "^5.2.1", | ||||
|     "nativewind": "^4.1.23", | ||||
|     "next": "14.2.33", | ||||
|     "react": "^18", | ||||
|     "react-aria": "^3.33.0", | ||||
|     "react-dom": "^18", | ||||
|     "react-native-reanimated": "~4.1.0", | ||||
|     "react-native-safe-area-context": "^5.6.1", | ||||
|     "react-native-svg": "^15.13.0", | ||||
|     "react-native-web": "^0.19.12", | ||||
|     "react-native-worklets": "^0.5.1", | ||||
|     "react-stately": "^3.39.0", | ||||
|     "tailwind-variants": "^0.1.20" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "@react-native/assets-registry": "^0.79.3", | ||||
|     "@types/node": "^20", | ||||
|     "@types/react": "^18", | ||||
|     "@types/react-dom": "^18", | ||||
|     "@types/react-native": "^0.72.8", | ||||
|     "autoprefixer": "^10.4.21", | ||||
|     "eslint": "^8", | ||||
|     "eslint-config-next": "14.2.33", | ||||
|     "postcss": "^8.5.4", | ||||
|     "tailwindcss": "^3.4.17", | ||||
|     "typescript": "^5" | ||||
|   } | ||||
| } | ||||
							
								
								
									
										8
									
								
								dashboard/postcss.config.mjs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								dashboard/postcss.config.mjs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| const config = { | ||||
|   plugins: { | ||||
|     tailwindcss: {}, | ||||
|     autoprefixer: {}, | ||||
|   }, | ||||
| }; | ||||
|  | ||||
| export default config; | ||||
							
								
								
									
										206
									
								
								dashboard/tailwind.config.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										206
									
								
								dashboard/tailwind.config.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,206 @@ | ||||
| /** @type {import('tailwindcss').Config} */ | ||||
| module.exports = { | ||||
|   darkMode: process.env.DARK_MODE ? process.env.DARK_MODE : 'class', | ||||
|   content: [ | ||||
|     './app/**/*.{html,js,jsx,ts,tsx,mdx}', | ||||
|     './components/**/*.{html,js,jsx,ts,tsx,mdx}', | ||||
|     './utils/**/*.{html,js,jsx,ts,tsx,mdx}', | ||||
|     './*.{html,js,jsx,ts,tsx,mdx}', | ||||
|     './src/**/*.{html,js,jsx,ts,tsx,mdx}', | ||||
|   ], | ||||
|   presets: [require('nativewind/preset')], | ||||
|   important: 'html', | ||||
|   safelist: [ | ||||
|     { | ||||
|       pattern: | ||||
|         /(bg|border|text|stroke|fill)-(primary|secondary|tertiary|error|success|warning|info|typography|outline|background|indicator)-(0|50|100|200|300|400|500|600|700|800|900|950|white|gray|black|error|warning|muted|success|info|light|dark|primary)/, | ||||
|     }, | ||||
|   ], | ||||
|   theme: { | ||||
|     extend: { | ||||
|       colors: { | ||||
|         primary: { | ||||
|           0: 'rgb(var(--color-primary-0)/<alpha-value>)', | ||||
|           50: 'rgb(var(--color-primary-50)/<alpha-value>)', | ||||
|           100: 'rgb(var(--color-primary-100)/<alpha-value>)', | ||||
|           200: 'rgb(var(--color-primary-200)/<alpha-value>)', | ||||
|           300: 'rgb(var(--color-primary-300)/<alpha-value>)', | ||||
|           400: 'rgb(var(--color-primary-400)/<alpha-value>)', | ||||
|           500: 'rgb(var(--color-primary-500)/<alpha-value>)', | ||||
|           600: 'rgb(var(--color-primary-600)/<alpha-value>)', | ||||
|           700: 'rgb(var(--color-primary-700)/<alpha-value>)', | ||||
|           800: 'rgb(var(--color-primary-800)/<alpha-value>)', | ||||
|           900: 'rgb(var(--color-primary-900)/<alpha-value>)', | ||||
|           950: 'rgb(var(--color-primary-950)/<alpha-value>)', | ||||
|         }, | ||||
|         secondary: { | ||||
|           0: 'rgb(var(--color-secondary-0)/<alpha-value>)', | ||||
|           50: 'rgb(var(--color-secondary-50)/<alpha-value>)', | ||||
|           100: 'rgb(var(--color-secondary-100)/<alpha-value>)', | ||||
|           200: 'rgb(var(--color-secondary-200)/<alpha-value>)', | ||||
|           300: 'rgb(var(--color-secondary-300)/<alpha-value>)', | ||||
|           400: 'rgb(var(--color-secondary-400)/<alpha-value>)', | ||||
|           500: 'rgb(var(--color-secondary-500)/<alpha-value>)', | ||||
|           600: 'rgb(var(--color-secondary-600)/<alpha-value>)', | ||||
|           700: 'rgb(var(--color-secondary-700)/<alpha-value>)', | ||||
|           800: 'rgb(var(--color-secondary-800)/<alpha-value>)', | ||||
|           900: 'rgb(var(--color-secondary-900)/<alpha-value>)', | ||||
|           950: 'rgb(var(--color-secondary-950)/<alpha-value>)', | ||||
|         }, | ||||
|         tertiary: { | ||||
|           50: 'rgb(var(--color-tertiary-50)/<alpha-value>)', | ||||
|           100: 'rgb(var(--color-tertiary-100)/<alpha-value>)', | ||||
|           200: 'rgb(var(--color-tertiary-200)/<alpha-value>)', | ||||
|           300: 'rgb(var(--color-tertiary-300)/<alpha-value>)', | ||||
|           400: 'rgb(var(--color-tertiary-400)/<alpha-value>)', | ||||
|           500: 'rgb(var(--color-tertiary-500)/<alpha-value>)', | ||||
|           600: 'rgb(var(--color-tertiary-600)/<alpha-value>)', | ||||
|           700: 'rgb(var(--color-tertiary-700)/<alpha-value>)', | ||||
|           800: 'rgb(var(--color-tertiary-800)/<alpha-value>)', | ||||
|           900: 'rgb(var(--color-tertiary-900)/<alpha-value>)', | ||||
|           950: 'rgb(var(--color-tertiary-950)/<alpha-value>)', | ||||
|         }, | ||||
|         error: { | ||||
|           0: 'rgb(var(--color-error-0)/<alpha-value>)', | ||||
|           50: 'rgb(var(--color-error-50)/<alpha-value>)', | ||||
|           100: 'rgb(var(--color-error-100)/<alpha-value>)', | ||||
|           200: 'rgb(var(--color-error-200)/<alpha-value>)', | ||||
|           300: 'rgb(var(--color-error-300)/<alpha-value>)', | ||||
|           400: 'rgb(var(--color-error-400)/<alpha-value>)', | ||||
|           500: 'rgb(var(--color-error-500)/<alpha-value>)', | ||||
|           600: 'rgb(var(--color-error-600)/<alpha-value>)', | ||||
|           700: 'rgb(var(--color-error-700)/<alpha-value>)', | ||||
|           800: 'rgb(var(--color-error-800)/<alpha-value>)', | ||||
|           900: 'rgb(var(--color-error-900)/<alpha-value>)', | ||||
|           950: 'rgb(var(--color-error-950)/<alpha-value>)', | ||||
|         }, | ||||
|         success: { | ||||
|           0: 'rgb(var(--color-success-0)/<alpha-value>)', | ||||
|           50: 'rgb(var(--color-success-50)/<alpha-value>)', | ||||
|           100: 'rgb(var(--color-success-100)/<alpha-value>)', | ||||
|           200: 'rgb(var(--color-success-200)/<alpha-value>)', | ||||
|           300: 'rgb(var(--color-success-300)/<alpha-value>)', | ||||
|           400: 'rgb(var(--color-success-400)/<alpha-value>)', | ||||
|           500: 'rgb(var(--color-success-500)/<alpha-value>)', | ||||
|           600: 'rgb(var(--color-success-600)/<alpha-value>)', | ||||
|           700: 'rgb(var(--color-success-700)/<alpha-value>)', | ||||
|           800: 'rgb(var(--color-success-800)/<alpha-value>)', | ||||
|           900: 'rgb(var(--color-success-900)/<alpha-value>)', | ||||
|           950: 'rgb(var(--color-success-950)/<alpha-value>)', | ||||
|         }, | ||||
|         warning: { | ||||
|           0: 'rgb(var(--color-warning-0)/<alpha-value>)', | ||||
|           50: 'rgb(var(--color-warning-50)/<alpha-value>)', | ||||
|           100: 'rgb(var(--color-warning-100)/<alpha-value>)', | ||||
|           200: 'rgb(var(--color-warning-200)/<alpha-value>)', | ||||
|           300: 'rgb(var(--color-warning-300)/<alpha-value>)', | ||||
|           400: 'rgb(var(--color-warning-400)/<alpha-value>)', | ||||
|           500: 'rgb(var(--color-warning-500)/<alpha-value>)', | ||||
|           600: 'rgb(var(--color-warning-600)/<alpha-value>)', | ||||
|           700: 'rgb(var(--color-warning-700)/<alpha-value>)', | ||||
|           800: 'rgb(var(--color-warning-800)/<alpha-value>)', | ||||
|           900: 'rgb(var(--color-warning-900)/<alpha-value>)', | ||||
|           950: 'rgb(var(--color-warning-950)/<alpha-value>)', | ||||
|         }, | ||||
|         info: { | ||||
|           0: 'rgb(var(--color-info-0)/<alpha-value>)', | ||||
|           50: 'rgb(var(--color-info-50)/<alpha-value>)', | ||||
|           100: 'rgb(var(--color-info-100)/<alpha-value>)', | ||||
|           200: 'rgb(var(--color-info-200)/<alpha-value>)', | ||||
|           300: 'rgb(var(--color-info-300)/<alpha-value>)', | ||||
|           400: 'rgb(var(--color-info-400)/<alpha-value>)', | ||||
|           500: 'rgb(var(--color-info-500)/<alpha-value>)', | ||||
|           600: 'rgb(var(--color-info-600)/<alpha-value>)', | ||||
|           700: 'rgb(var(--color-info-700)/<alpha-value>)', | ||||
|           800: 'rgb(var(--color-info-800)/<alpha-value>)', | ||||
|           900: 'rgb(var(--color-info-900)/<alpha-value>)', | ||||
|           950: 'rgb(var(--color-info-950)/<alpha-value>)', | ||||
|         }, | ||||
|         typography: { | ||||
|           0: 'rgb(var(--color-typography-0)/<alpha-value>)', | ||||
|           50: 'rgb(var(--color-typography-50)/<alpha-value>)', | ||||
|           100: 'rgb(var(--color-typography-100)/<alpha-value>)', | ||||
|           200: 'rgb(var(--color-typography-200)/<alpha-value>)', | ||||
|           300: 'rgb(var(--color-typography-300)/<alpha-value>)', | ||||
|           400: 'rgb(var(--color-typography-400)/<alpha-value>)', | ||||
|           500: 'rgb(var(--color-typography-500)/<alpha-value>)', | ||||
|           600: 'rgb(var(--color-typography-600)/<alpha-value>)', | ||||
|           700: 'rgb(var(--color-typography-700)/<alpha-value>)', | ||||
|           800: 'rgb(var(--color-typography-800)/<alpha-value>)', | ||||
|           900: 'rgb(var(--color-typography-900)/<alpha-value>)', | ||||
|           950: 'rgb(var(--color-typography-950)/<alpha-value>)', | ||||
|           white: '#FFFFFF', | ||||
|           gray: '#D4D4D4', | ||||
|           black: '#181718', | ||||
|         }, | ||||
|         outline: { | ||||
|           0: 'rgb(var(--color-outline-0)/<alpha-value>)', | ||||
|           50: 'rgb(var(--color-outline-50)/<alpha-value>)', | ||||
|           100: 'rgb(var(--color-outline-100)/<alpha-value>)', | ||||
|           200: 'rgb(var(--color-outline-200)/<alpha-value>)', | ||||
|           300: 'rgb(var(--color-outline-300)/<alpha-value>)', | ||||
|           400: 'rgb(var(--color-outline-400)/<alpha-value>)', | ||||
|           500: 'rgb(var(--color-outline-500)/<alpha-value>)', | ||||
|           600: 'rgb(var(--color-outline-600)/<alpha-value>)', | ||||
|           700: 'rgb(var(--color-outline-700)/<alpha-value>)', | ||||
|           800: 'rgb(var(--color-outline-800)/<alpha-value>)', | ||||
|           900: 'rgb(var(--color-outline-900)/<alpha-value>)', | ||||
|           950: 'rgb(var(--color-outline-950)/<alpha-value>)', | ||||
|         }, | ||||
|         background: { | ||||
|           0: 'rgb(var(--color-background-0)/<alpha-value>)', | ||||
|           50: 'rgb(var(--color-background-50)/<alpha-value>)', | ||||
|           100: 'rgb(var(--color-background-100)/<alpha-value>)', | ||||
|           200: 'rgb(var(--color-background-200)/<alpha-value>)', | ||||
|           300: 'rgb(var(--color-background-300)/<alpha-value>)', | ||||
|           400: 'rgb(var(--color-background-400)/<alpha-value>)', | ||||
|           500: 'rgb(var(--color-background-500)/<alpha-value>)', | ||||
|           600: 'rgb(var(--color-background-600)/<alpha-value>)', | ||||
|           700: 'rgb(var(--color-background-700)/<alpha-value>)', | ||||
|           800: 'rgb(var(--color-background-800)/<alpha-value>)', | ||||
|           900: 'rgb(var(--color-background-900)/<alpha-value>)', | ||||
|           950: 'rgb(var(--color-background-950)/<alpha-value>)', | ||||
|           error: 'rgb(var(--color-background-error)/<alpha-value>)', | ||||
|           warning: 'rgb(var(--color-background-warning)/<alpha-value>)', | ||||
|           muted: 'rgb(var(--color-background-muted)/<alpha-value>)', | ||||
|           success: 'rgb(var(--color-background-success)/<alpha-value>)', | ||||
|           info: 'rgb(var(--color-background-info)/<alpha-value>)', | ||||
|           light: '#FBFBFB', | ||||
|           dark: '#181719', | ||||
|         }, | ||||
|         indicator: { | ||||
|           primary: 'rgb(var(--color-indicator-primary)/<alpha-value>)', | ||||
|           info: 'rgb(var(--color-indicator-info)/<alpha-value>)', | ||||
|           error: 'rgb(var(--color-indicator-error)/<alpha-value>)', | ||||
|         }, | ||||
|       }, | ||||
|       fontFamily: { | ||||
|         heading: undefined, | ||||
|         body: undefined, | ||||
|         mono: undefined, | ||||
|         jakarta: ['var(--font-plus-jakarta-sans)'], | ||||
|         roboto: ['var(--font-roboto)'], | ||||
|         code: ['var(--font-source-code-pro)'], | ||||
|         inter: ['var(--font-inter)'], | ||||
|         'space-mono': ['var(--font-space-mono)'], | ||||
|       }, | ||||
|       fontWeight: { | ||||
|         extrablack: '950', | ||||
|       }, | ||||
|       fontSize: { | ||||
|         '2xs': '10px', | ||||
|       }, | ||||
|       boxShadow: { | ||||
|         'hard-1': '-2px 2px 8px 0px rgba(38, 38, 38, 0.20)', | ||||
|         'hard-2': '0px 3px 10px 0px rgba(38, 38, 38, 0.20)', | ||||
|         'hard-3': '2px 2px 8px 0px rgba(38, 38, 38, 0.20)', | ||||
|         'hard-4': '0px -3px 10px 0px rgba(38, 38, 38, 0.20)', | ||||
|         'hard-5': '0px 2px 10px 0px rgba(38, 38, 38, 0.10)', | ||||
|         'soft-1': '0px 0px 10px rgba(38, 38, 38, 0.1)', | ||||
|         'soft-2': '0px 0px 20px rgba(38, 38, 38, 0.2)', | ||||
|         'soft-3': '0px 0px 30px rgba(38, 38, 38, 0.1)', | ||||
|         'soft-4': '0px 0px 40px rgba(38, 38, 38, 0.1)', | ||||
|       }, | ||||
|     }, | ||||
|   }, | ||||
| }; | ||||
							
								
								
									
										43
									
								
								dashboard/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								dashboard/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| { | ||||
|   "compilerOptions": { | ||||
|     "lib": [ | ||||
|       "dom", | ||||
|       "dom.iterable", | ||||
|       "esnext" | ||||
|     ], | ||||
|     "allowJs": true, | ||||
|     "skipLibCheck": true, | ||||
|     "strict": true, | ||||
|     "noEmit": true, | ||||
|     "esModuleInterop": true, | ||||
|     "module": "esnext", | ||||
|     "moduleResolution": "bundler", | ||||
|     "resolveJsonModule": true, | ||||
|     "isolatedModules": true, | ||||
|     "jsx": "preserve", | ||||
|     "incremental": true, | ||||
|     "plugins": [ | ||||
|       { | ||||
|         "name": "next" | ||||
|       } | ||||
|     ], | ||||
|     "paths": { | ||||
|       "@/*": [ | ||||
|         "./*" | ||||
|       ], | ||||
|       "tailwind.config": [ | ||||
|         "./tailwind.config.ts" | ||||
|       ] | ||||
|     }, | ||||
|     "jsxImportSource": "nativewind" | ||||
|   }, | ||||
|   "include": [ | ||||
|     "next-env.d.ts", | ||||
|     "**/*.ts", | ||||
|     "**/*.tsx", | ||||
|     ".next/types/**/*.ts" | ||||
|   ], | ||||
|   "exclude": [ | ||||
|     "node_modules" | ||||
|   ] | ||||
| } | ||||
		Reference in New Issue
	
	Block a user