update to tailwind config for screen sizes, added all images for first batch of products
@ -23,6 +23,7 @@ app.config["SESSION_USE_SIGNER"] = True
|
||||
app.config["SESSION_REDIS"] = redis.from_url("redis://192.168.50.107:6379")
|
||||
# upload directory
|
||||
app.config["UPLOAD_DIRECTORY"] = 'uploads/'
|
||||
# app.config["UPLOAD_DIRECTORY"] = '../frontend/public/Group_1'
|
||||
# app.config["REDIS_PASSWORD"] = os.environ["REDIS_PASSWORD"]
|
||||
|
||||
# File value limit
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
"tailwind": {
|
||||
"config": "tailwind.config.ts",
|
||||
"css": "src/app/globals.css",
|
||||
"baseColor": "gray",
|
||||
"baseColor": "slate",
|
||||
"cssVariables": true,
|
||||
"prefix": ""
|
||||
},
|
||||
|
||||
@ -9,14 +9,15 @@
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@radix-ui/react-slot": "^1.1.0",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "^2.1.0",
|
||||
"lucide-react": "^0.365.0",
|
||||
"clsx": "^2.1.1",
|
||||
"lucide-react": "^0.427.0",
|
||||
"next": "14.1.4",
|
||||
"react": "^18",
|
||||
"react-dom": "^18",
|
||||
"react-dom": "^18.3.1",
|
||||
"sharp": "^0.33.4",
|
||||
"tailwind-merge": "^2.2.2",
|
||||
"tailwind-merge": "^2.5.0",
|
||||
"tailwindcss-animate": "^1.0.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
BIN
frontend/public/Group_1/Mockup_97.jpg
Normal file
|
After Width: | Height: | Size: 219 KiB |
BIN
frontend/public/Group_1/design_4-01.png
Normal file
|
After Width: | Height: | Size: 867 KiB |
BIN
frontend/public/Group_1/design_7_update-01.png
Normal file
|
After Width: | Height: | Size: 619 KiB |
BIN
frontend/public/Group_1/design_8_update-01.png
Normal file
|
After Width: | Height: | Size: 732 KiB |
BIN
frontend/public/Group_1/design_update.png
Normal file
|
After Width: | Height: | Size: 505 KiB |
92
frontend/public/Group_1/files_list.json
Normal file
@ -0,0 +1,92 @@
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"name": "files_list",
|
||||
"photo": "/files_list.json",
|
||||
"price": 25,
|
||||
"size": "Youth-S/M/L/2XL | Adult-S/M/L/2XL",
|
||||
"inStock": "yes",
|
||||
"favorite": "no",
|
||||
"description": "It's not an option.."
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "design_8_update-01",
|
||||
"photo": "/design_8_update-01.png",
|
||||
"price": 25,
|
||||
"size": "Youth-S/M/L/2XL | Adult-S/M/L/2XL",
|
||||
"inStock": "yes",
|
||||
"favorite": "no",
|
||||
"description": "It's not an option.."
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Mockup_97",
|
||||
"photo": "/Mockup_97.jpg",
|
||||
"price": 25,
|
||||
"size": "Youth-S/M/L/2XL | Adult-S/M/L/2XL",
|
||||
"inStock": "yes",
|
||||
"favorite": "no",
|
||||
"description": "It's not an option.."
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "json_sorter",
|
||||
"photo": "/json_sorter.py",
|
||||
"price": 25,
|
||||
"size": "Youth-S/M/L/2XL | Adult-S/M/L/2XL",
|
||||
"inStock": "yes",
|
||||
"favorite": "no",
|
||||
"description": "It's not an option.."
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"name": "design_update",
|
||||
"photo": "/design_update.png",
|
||||
"price": 25,
|
||||
"size": "Youth-S/M/L/2XL | Adult-S/M/L/2XL",
|
||||
"inStock": "yes",
|
||||
"favorite": "no",
|
||||
"description": "It's not an option.."
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"name": "design_4-01",
|
||||
"photo": "/design_4-01.png",
|
||||
"price": 25,
|
||||
"size": "Youth-S/M/L/2XL | Adult-S/M/L/2XL",
|
||||
"inStock": "yes",
|
||||
"favorite": "no",
|
||||
"description": "It's not an option.."
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"name": "design_7_update-01",
|
||||
"photo": "/design_7_update-01.png",
|
||||
"price": 25,
|
||||
"size": "Youth-S/M/L/2XL | Adult-S/M/L/2XL",
|
||||
"inStock": "yes",
|
||||
"favorite": "no",
|
||||
"description": "It's not an option.."
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"name": "test_design_never_give_up-01",
|
||||
"photo": "/test_design_never_give_up-01.png",
|
||||
"price": 25,
|
||||
"size": "Youth-S/M/L/2XL | Adult-S/M/L/2XL",
|
||||
"inStock": "yes",
|
||||
"favorite": "no",
|
||||
"description": "It's not an option.."
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"name": "mockup_1",
|
||||
"photo": "/mockup_1.jpg",
|
||||
"price": 25,
|
||||
"size": "Youth-S/M/L/2XL | Adult-S/M/L/2XL",
|
||||
"inStock": "yes",
|
||||
"favorite": "no",
|
||||
"description": "It's not an option.."
|
||||
}
|
||||
]
|
||||
BIN
frontend/public/Group_1/mockup_1.jpg
Normal file
|
After Width: | Height: | Size: 2.1 MiB |
BIN
frontend/public/Group_1/test_design_never_give_up-01.png
Normal file
|
After Width: | Height: | Size: 979 KiB |
BIN
frontend/public/batch1/10-01.png
Normal file
|
After Width: | Height: | Size: 5.6 MiB |
BIN
frontend/public/batch1/13 UPDATE DESIGN.jpg
Normal file
|
After Width: | Height: | Size: 221 KiB |
BIN
frontend/public/batch1/75-01.png
Normal file
|
After Width: | Height: | Size: 5.4 MiB |
BIN
frontend/public/batch1/Mockup 106.jpg
Normal file
|
After Width: | Height: | Size: 223 KiB |
BIN
frontend/public/batch1/Mockup 112.jpg
Normal file
|
After Width: | Height: | Size: 209 KiB |
BIN
frontend/public/batch1/Mockup 113.jpg
Normal file
|
After Width: | Height: | Size: 243 KiB |
BIN
frontend/public/batch1/Mockup 119.jpg
Normal file
|
After Width: | Height: | Size: 252 KiB |
BIN
frontend/public/batch1/Mockup 126 new.jpg
Normal file
|
After Width: | Height: | Size: 237 KiB |
BIN
frontend/public/batch1/Mockup 134.jpg
Normal file
|
After Width: | Height: | Size: 238 KiB |
BIN
frontend/public/batch1/Mockup 16 update.jpg
Normal file
|
After Width: | Height: | Size: 228 KiB |
BIN
frontend/public/batch1/Mockup 18.jpg
Normal file
|
After Width: | Height: | Size: 240 KiB |
BIN
frontend/public/batch1/Mockup 23.jpg
Normal file
|
After Width: | Height: | Size: 218 KiB |
BIN
frontend/public/batch1/Mockup 37.jpg
Normal file
|
After Width: | Height: | Size: 268 KiB |
BIN
frontend/public/batch1/Mockup 66.jpg
Normal file
|
After Width: | Height: | Size: 264 KiB |
BIN
frontend/public/batch1/Mockup 73.jpg
Normal file
|
After Width: | Height: | Size: 226 KiB |
BIN
frontend/public/batch1/Mockup 97.jpg
Normal file
|
After Width: | Height: | Size: 219 KiB |
BIN
frontend/public/batch1/design 4-01.png
Normal file
|
After Width: | Height: | Size: 867 KiB |
BIN
frontend/public/batch1/design 6 update-01.png
Normal file
|
After Width: | Height: | Size: 1.8 MiB |
BIN
frontend/public/batch1/design 7 update-01.png
Normal file
|
After Width: | Height: | Size: 619 KiB |
BIN
frontend/public/batch1/design 8 update-01.png
Normal file
|
After Width: | Height: | Size: 732 KiB |
BIN
frontend/public/batch1/design update.png
Normal file
|
After Width: | Height: | Size: 505 KiB |
212
frontend/public/batch1/files_list.json
Normal file
@ -0,0 +1,212 @@
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"name": "design update",
|
||||
"photo": "batch1/design update.png",
|
||||
"price": 25,
|
||||
"size": "Youth-S/M/L/2XL | Adult-S/M/L/2XL",
|
||||
"inStock": "yes",
|
||||
"favorite": "no",
|
||||
"description": "It's not an option.."
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Mockup 134",
|
||||
"photo": "batch1/Mockup 134.jpg",
|
||||
"price": 25,
|
||||
"size": "Youth-S/M/L/2XL | Adult-S/M/L/2XL",
|
||||
"inStock": "yes",
|
||||
"favorite": "no",
|
||||
"description": "It's not an option.."
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Mockup 126 new",
|
||||
"photo": "batch1/Mockup 126 new.jpg",
|
||||
"price": 25,
|
||||
"size": "Youth-S/M/L/2XL | Adult-S/M/L/2XL",
|
||||
"inStock": "yes",
|
||||
"favorite": "no",
|
||||
"description": "It's not an option.."
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "Mockup 113",
|
||||
"photo": "batch1/Mockup 113.jpg",
|
||||
"price": 25,
|
||||
"size": "Youth-S/M/L/2XL | Adult-S/M/L/2XL",
|
||||
"inStock": "yes",
|
||||
"favorite": "no",
|
||||
"description": "It's not an option.."
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"name": "design 6 update-01",
|
||||
"photo": "batch1/design 6 update-01.png",
|
||||
"price": 25,
|
||||
"size": "Youth-S/M/L/2XL | Adult-S/M/L/2XL",
|
||||
"inStock": "yes",
|
||||
"favorite": "no",
|
||||
"description": "It's not an option.."
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"name": "Mockup 37",
|
||||
"photo": "batch1/Mockup 37.jpg",
|
||||
"price": 25,
|
||||
"size": "Youth-S/M/L/2XL | Adult-S/M/L/2XL",
|
||||
"inStock": "yes",
|
||||
"favorite": "no",
|
||||
"description": "It's not an option.."
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"name": "Mockup 106",
|
||||
"photo": "batch1/Mockup 106.jpg",
|
||||
"price": 25,
|
||||
"size": "Youth-S/M/L/2XL | Adult-S/M/L/2XL",
|
||||
"inStock": "yes",
|
||||
"favorite": "no",
|
||||
"description": "It's not an option.."
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"name": "design 4-01",
|
||||
"photo": "batch1/design 4-01.png",
|
||||
"price": 25,
|
||||
"size": "Youth-S/M/L/2XL | Adult-S/M/L/2XL",
|
||||
"inStock": "yes",
|
||||
"favorite": "no",
|
||||
"description": "It's not an option.."
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"name": "Mockup 97",
|
||||
"photo": "batch1/Mockup 97.jpg",
|
||||
"price": 25,
|
||||
"size": "Youth-S/M/L/2XL | Adult-S/M/L/2XL",
|
||||
"inStock": "yes",
|
||||
"favorite": "no",
|
||||
"description": "It's not an option.."
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"name": "Mockup 112",
|
||||
"photo": "batch1/Mockup 112.jpg",
|
||||
"price": 25,
|
||||
"size": "Youth-S/M/L/2XL | Adult-S/M/L/2XL",
|
||||
"inStock": "yes",
|
||||
"favorite": "no",
|
||||
"description": "It's not an option.."
|
||||
},
|
||||
{
|
||||
"id": 12,
|
||||
"name": "75-01",
|
||||
"photo": "batch1/75-01.png",
|
||||
"price": 25,
|
||||
"size": "Youth-S/M/L/2XL | Adult-S/M/L/2XL",
|
||||
"inStock": "yes",
|
||||
"favorite": "no",
|
||||
"description": "It's not an option.."
|
||||
},
|
||||
{
|
||||
"id": 13,
|
||||
"name": "Mockup 119",
|
||||
"photo": "batch1/Mockup 119.jpg",
|
||||
"price": 25,
|
||||
"size": "Youth-S/M/L/2XL | Adult-S/M/L/2XL",
|
||||
"inStock": "yes",
|
||||
"favorite": "no",
|
||||
"description": "It's not an option.."
|
||||
},
|
||||
{
|
||||
"id": 14,
|
||||
"name": "Mockup 16 update",
|
||||
"photo": "batch1/Mockup 16 update.jpg",
|
||||
"price": 25,
|
||||
"size": "Youth-S/M/L/2XL | Adult-S/M/L/2XL",
|
||||
"inStock": "yes",
|
||||
"favorite": "no",
|
||||
"description": "It's not an option.."
|
||||
},
|
||||
{
|
||||
"id": 15,
|
||||
"name": "10-01",
|
||||
"photo": "batch1/10-01.png",
|
||||
"price": 25,
|
||||
"size": "Youth-S/M/L/2XL | Adult-S/M/L/2XL",
|
||||
"inStock": "yes",
|
||||
"favorite": "no",
|
||||
"description": "It's not an option.."
|
||||
},
|
||||
{
|
||||
"id": 16,
|
||||
"name": "design 7 update-01",
|
||||
"photo": "batch1/design 7 update-01.png",
|
||||
"price": 25,
|
||||
"size": "Youth-S/M/L/2XL | Adult-S/M/L/2XL",
|
||||
"inStock": "yes",
|
||||
"favorite": "no",
|
||||
"description": "It's not an option.."
|
||||
},
|
||||
{
|
||||
"id": 17,
|
||||
"name": "Mockup 18",
|
||||
"photo": "batch1/Mockup 18.jpg",
|
||||
"price": 25,
|
||||
"size": "Youth-S/M/L/2XL | Adult-S/M/L/2XL",
|
||||
"inStock": "yes",
|
||||
"favorite": "no",
|
||||
"description": "It's not an option.."
|
||||
},
|
||||
{
|
||||
"id": 18,
|
||||
"name": "13 UPDATE DESIGN",
|
||||
"photo": "batch1/13 UPDATE DESIGN.jpg",
|
||||
"price": 25,
|
||||
"size": "Youth-S/M/L/2XL | Adult-S/M/L/2XL",
|
||||
"inStock": "yes",
|
||||
"favorite": "no",
|
||||
"description": "It's not an option.."
|
||||
},
|
||||
{
|
||||
"id": 19,
|
||||
"name": "Mockup 66",
|
||||
"photo": "batch1/Mockup 66.jpg",
|
||||
"price": 25,
|
||||
"size": "Youth-S/M/L/2XL | Adult-S/M/L/2XL",
|
||||
"inStock": "yes",
|
||||
"favorite": "no",
|
||||
"description": "It's not an option.."
|
||||
},
|
||||
{
|
||||
"id": 20,
|
||||
"name": "design 8 update-01",
|
||||
"photo": "batch1/design 8 update-01.png",
|
||||
"price": 25,
|
||||
"size": "Youth-S/M/L/2XL | Adult-S/M/L/2XL",
|
||||
"inStock": "yes",
|
||||
"favorite": "no",
|
||||
"description": "It's not an option.."
|
||||
},
|
||||
{
|
||||
"id": 21,
|
||||
"name": "Mockup 23",
|
||||
"photo": "batch1/Mockup 23.jpg",
|
||||
"price": 25,
|
||||
"size": "Youth-S/M/L/2XL | Adult-S/M/L/2XL",
|
||||
"inStock": "yes",
|
||||
"favorite": "no",
|
||||
"description": "It's not an option.."
|
||||
},
|
||||
{
|
||||
"id": 22,
|
||||
"name": "Mockup 73",
|
||||
"photo": "batch1/Mockup 73.jpg",
|
||||
"price": 25,
|
||||
"size": "Youth-S/M/L/2XL | Adult-S/M/L/2XL",
|
||||
"inStock": "yes",
|
||||
"favorite": "no",
|
||||
"description": "It's not an option.."
|
||||
}
|
||||
]
|
||||
36
frontend/public/batch1/json_sorter.py
Normal file
@ -0,0 +1,36 @@
|
||||
import os
|
||||
import json
|
||||
|
||||
def list_files_in_directory(directory_path):
|
||||
# Get a list of all files in the directory with their respective attributes
|
||||
files_list = []
|
||||
file_id = 1
|
||||
|
||||
for root, dirs, files in os.walk(directory_path):
|
||||
for file in files:
|
||||
file_data = {
|
||||
"id": file_id,
|
||||
"name": os.path.splitext(file)[0],
|
||||
"photo": f'{os.path.dirname(directory_path)}/{file}',
|
||||
"price": 25, # Default price, change as needed
|
||||
"size": "Youth-S/M/L/2XL | Adult-S/M/L/2XL", # Default size, change as needed
|
||||
"inStock": "yes", # Default stock status, change as needed
|
||||
"favorite": "no", # Default favorite status, change as needed
|
||||
"description": "It's not an option.." # Default description, change as needed
|
||||
}
|
||||
files_list.append(file_data)
|
||||
file_id += 1
|
||||
|
||||
return files_list
|
||||
|
||||
def write_files_to_json(directory_path, output_json_file):
|
||||
files_list = list_files_in_directory(directory_path)
|
||||
|
||||
# Write the list to a JSON file
|
||||
with open(output_json_file, 'w') as json_file:
|
||||
json.dump(files_list, json_file, indent=4)
|
||||
|
||||
# Example usage
|
||||
directory_path = '.'
|
||||
output_json_file = f'files_list.json'
|
||||
write_files_to_json(directory_path, output_json_file)
|
||||
82
frontend/public/files_list.json
Normal file
@ -0,0 +1,82 @@
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"name": "files_list",
|
||||
"photo": "./files_list.json",
|
||||
"price": 25,
|
||||
"size": "Youth-S/M/L/2XL | Adult-S/M/L/2XL",
|
||||
"inStock": "yes",
|
||||
"favorite": "no",
|
||||
"description": "It's not an option.."
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "design_8_update-01",
|
||||
"photo": "./design_8_update-01.png",
|
||||
"price": 25,
|
||||
"size": "Youth-S/M/L/2XL | Adult-S/M/L/2XL",
|
||||
"inStock": "yes",
|
||||
"favorite": "no",
|
||||
"description": "It's not an option.."
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Mockup_97",
|
||||
"photo": "./Mockup_97.jpg",
|
||||
"price": 25,
|
||||
"size": "Youth-S/M/L/2XL | Adult-S/M/L/2XL",
|
||||
"inStock": "yes",
|
||||
"favorite": "no",
|
||||
"description": "It's not an option.."
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "design_update",
|
||||
"photo": "./design_update.png",
|
||||
"price": 25,
|
||||
"size": "Youth-S/M/L/2XL | Adult-S/M/L/2XL",
|
||||
"inStock": "yes",
|
||||
"favorite": "no",
|
||||
"description": "It's not an option.."
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"name": "design_4-01",
|
||||
"photo": "./design_4-01.png",
|
||||
"price": 25,
|
||||
"size": "Youth-S/M/L/2XL | Adult-S/M/L/2XL",
|
||||
"inStock": "yes",
|
||||
"favorite": "no",
|
||||
"description": "It's not an option.."
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"name": "design_7_update-01",
|
||||
"photo": "./design_7_update-01.png",
|
||||
"price": 25,
|
||||
"size": "Youth-S/M/L/2XL | Adult-S/M/L/2XL",
|
||||
"inStock": "yes",
|
||||
"favorite": "no",
|
||||
"description": "It's not an option.."
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"name": "test_design_never_give_up-01",
|
||||
"photo": "./test_design_never_give_up-01.png",
|
||||
"price": 25,
|
||||
"size": "Youth-S/M/L/2XL | Adult-S/M/L/2XL",
|
||||
"inStock": "yes",
|
||||
"favorite": "no",
|
||||
"description": "It's not an option.."
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"name": "mockup_1",
|
||||
"photo": "./mockup_1.jpg",
|
||||
"price": 25,
|
||||
"size": "Youth-S/M/L/2XL | Adult-S/M/L/2XL",
|
||||
"inStock": "yes",
|
||||
"favorite": "no",
|
||||
"description": "It's not an option.."
|
||||
}
|
||||
]
|
||||
17
frontend/src/app/_document.tsx
Normal file
@ -0,0 +1,17 @@
|
||||
//pages/_document.tsx
|
||||
import { poppins } from "@/components/ClientPortal/ClientPortal";
|
||||
import { Html, Head, Main, NextScript } from "next/document";
|
||||
|
||||
|
||||
export default function Document() {
|
||||
return (
|
||||
<Html lang="en" className={poppins.className}>
|
||||
<Head />
|
||||
<body >
|
||||
<Main />
|
||||
<div id="myportal" />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
);
|
||||
}
|
||||
@ -1,76 +1,69 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 224 71.4% 4.1%;
|
||||
|
||||
--card: 0 0% 100%;
|
||||
--card-foreground: 224 71.4% 4.1%;
|
||||
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 224 71.4% 4.1%;
|
||||
|
||||
--primary: 220.9 39.3% 11%;
|
||||
--primary-foreground: 210 20% 98%;
|
||||
|
||||
--secondary: 220 14.3% 95.9%;
|
||||
--secondary-foreground: 220.9 39.3% 11%;
|
||||
|
||||
--muted: 220 14.3% 95.9%;
|
||||
--muted-foreground: 220 8.9% 46.1%;
|
||||
|
||||
--accent: 220 14.3% 95.9%;
|
||||
--accent-foreground: 220.9 39.3% 11%;
|
||||
|
||||
--destructive: 0 84.2% 60.2%;
|
||||
--destructive-foreground: 210 20% 98%;
|
||||
|
||||
--border: 220 13% 91%;
|
||||
--input: 220 13% 91%;
|
||||
--ring: 224 71.4% 4.1%;
|
||||
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: 224 71.4% 4.1%;
|
||||
--foreground: 210 20% 98%;
|
||||
|
||||
--card: 224 71.4% 4.1%;
|
||||
--card-foreground: 210 20% 98%;
|
||||
|
||||
--popover: 224 71.4% 4.1%;
|
||||
--popover-foreground: 210 20% 98%;
|
||||
|
||||
--primary: 210 20% 98%;
|
||||
--primary-foreground: 220.9 39.3% 11%;
|
||||
|
||||
--secondary: 215 27.9% 16.9%;
|
||||
--secondary-foreground: 210 20% 98%;
|
||||
|
||||
--muted: 215 27.9% 16.9%;
|
||||
--muted-foreground: 217.9 10.6% 64.9%;
|
||||
|
||||
--accent: 215 27.9% 16.9%;
|
||||
--accent-foreground: 210 20% 98%;
|
||||
|
||||
--destructive: 0 62.8% 30.6%;
|
||||
--destructive-foreground: 210 20% 98%;
|
||||
|
||||
--border: 215 27.9% 16.9%;
|
||||
--input: 215 27.9% 16.9%;
|
||||
--ring: 216 12.2% 83.9%;
|
||||
}
|
||||
@layer base {
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 222.2 84% 4.9%;
|
||||
--card: 0 0% 100%;
|
||||
--card-foreground: 222.2 84% 4.9%;
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 222.2 84% 4.9%;
|
||||
--primary: 222.2 47.4% 11.2%;
|
||||
--primary-foreground: 210 40% 98%;
|
||||
--secondary: 210 40% 96.1%;
|
||||
--secondary-foreground: 222.2 47.4% 11.2%;
|
||||
--muted: 210 40% 96.1%;
|
||||
--muted-foreground: 215.4 16.3% 46.9%;
|
||||
--accent: 210 40% 96.1%;
|
||||
--accent-foreground: 222.2 47.4% 11.2%;
|
||||
--destructive: 0 84.2% 60.2%;
|
||||
--destructive-foreground: 210 40% 98%;
|
||||
--border: 214.3 31.8% 91.4%;
|
||||
--input: 214.3 31.8% 91.4%;
|
||||
--ring: 222.2 84% 4.9%;
|
||||
--radius: 0.5rem;
|
||||
--chart-1: 12 76% 61%;
|
||||
--chart-2: 173 58% 39%;
|
||||
--chart-3: 197 37% 24%;
|
||||
--chart-4: 43 74% 66%;
|
||||
--chart-5: 27 87% 67%;
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border;
|
||||
}
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
}
|
||||
}
|
||||
.dark {
|
||||
--background: 222.2 84% 4.9%;
|
||||
--foreground: 210 40% 98%;
|
||||
--card: 222.2 84% 4.9%;
|
||||
--card-foreground: 210 40% 98%;
|
||||
--popover: 222.2 84% 4.9%;
|
||||
--popover-foreground: 210 40% 98%;
|
||||
--primary: 210 40% 98%;
|
||||
--primary-foreground: 222.2 47.4% 11.2%;
|
||||
--secondary: 217.2 32.6% 17.5%;
|
||||
--secondary-foreground: 210 40% 98%;
|
||||
--muted: 217.2 32.6% 17.5%;
|
||||
--muted-foreground: 215 20.2% 65.1%;
|
||||
--accent: 217.2 32.6% 17.5%;
|
||||
--accent-foreground: 210 40% 98%;
|
||||
--destructive: 0 62.8% 30.6%;
|
||||
--destructive-foreground: 210 40% 98%;
|
||||
--border: 217.2 32.6% 17.5%;
|
||||
--input: 217.2 32.6% 17.5%;
|
||||
--ring: 212.7 26.8% 83.9%;
|
||||
--chart-1: 220 70% 50%;
|
||||
--chart-2: 160 60% 45%;
|
||||
--chart-3: 30 80% 55%;
|
||||
--chart-4: 280 65% 60%;
|
||||
--chart-5: 340 75% 55%;
|
||||
}
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border;
|
||||
}
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
}
|
||||
}
|
||||
77
frontend/src/app/index.tsx
Normal file
@ -0,0 +1,77 @@
|
||||
//pages/index.tsx
|
||||
import { useState } from "react";
|
||||
import styles from "@/styles/Home.module.css";
|
||||
import ClientPortal from "../components/ClientPortal/ClientPortal";
|
||||
export default function Home() {
|
||||
const [showPortal, setShowPortal] = useState(false);
|
||||
const handleModal = () => {
|
||||
setShowPortal(!showPortal);
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<main className={`${styles.main}`}>
|
||||
<h1>Implementation portal in next JS</h1>
|
||||
<button onClick={handleModal} className={styles.btn}>
|
||||
Read Blog
|
||||
</button>
|
||||
</main>
|
||||
<ClientPortal
|
||||
selector="myportal"
|
||||
show={showPortal}
|
||||
>
|
||||
<div className={styles.overflow}>
|
||||
<div className={styles.modal}>
|
||||
<div className={styles.header}>
|
||||
<h4>Lorem Ipsum</h4>
|
||||
<button onClick={handleModal} className={styles.removeButton}>
|
||||
{/* <button className={styles.removeButton}> */}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
height="1em"
|
||||
viewBox="0 0 384 512"
|
||||
>
|
||||
<path d="M342.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L192 210.7 86.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L146.7 256 41.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L192 301.3 297.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L237.3 256 342.6 150.6z" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div className={styles.body}>
|
||||
<p>
|
||||
Basically, React Portal is a powerful technique to create a
|
||||
first-class way to render children into a DOM (Document object
|
||||
modal) Node from outside of their parent component hierarchy.
|
||||
</p>
|
||||
<div className={styles.reactontent}>
|
||||
<h4>Industry's stand 1960s with the release</h4>
|
||||
<p>
|
||||
has been the industry's stand 1960s with the release of
|
||||
Letraset sheets containing Lorem Ipsum passages, and more
|
||||
recently with desktop publishing software like Aldus PageMaker
|
||||
including versions of Lorem Ipsum.
|
||||
</p>
|
||||
</div>
|
||||
<div className={styles.reactontent}>
|
||||
<p>
|
||||
Lorem Ipsum is simply dummy text of the printing It has
|
||||
survived not only five centuries, but also the leap into
|
||||
electronic typesetting, remaining essentially unchanged. It
|
||||
was popularised in the 1960s with the release of Letraset
|
||||
sheets containing Lorem Ipsum passages, and more recently
|
||||
</p>
|
||||
</div>
|
||||
<div className={styles.reactontent}>
|
||||
<p>
|
||||
Lorem Ipsum is simply dummy text of the printing and
|
||||
typesetting industry. Lorem Ipsum has been the industry's
|
||||
standard dummy text ever since the 1500s, when an unknown
|
||||
printer took a galley of type and Lorem Ipsum.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ClientPortal>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@ -1,9 +1,20 @@
|
||||
"use client";
|
||||
import * as React from "react";
|
||||
import Image from "next/image";
|
||||
import MenuCard from "../components/ui/MenuCard/MenuCard";
|
||||
import Product from "./products.json";
|
||||
import { cn } from "../lib/utils";
|
||||
import Product from "../../public/Group_1/files_list.json";
|
||||
import { Button } from "../components/ui/button";
|
||||
import Modal from "../components/Modal/Modal";
|
||||
import ClientPortal from "@/components/ClientPortal/ClientPortal";
|
||||
import styles from "@/styles/Home.module.css";
|
||||
|
||||
export default function Home() {
|
||||
const [isOpen, setIsOpen] = React.useState(false);
|
||||
const [showPortal, setShowPortal] = React.useState(false);
|
||||
const handleModal = () => {
|
||||
setShowPortal(!showPortal);
|
||||
};
|
||||
|
||||
return (
|
||||
<main className="flex min-h-screen flex-col px-20 bg-[#F5F5F5">
|
||||
{/* Title */}
|
||||
@ -16,12 +27,21 @@ export default function Home() {
|
||||
<MenuCard Menu={Product} />
|
||||
</div>
|
||||
|
||||
{/* <div>
|
||||
<Button onClick={() => setIsOpen(true)}>Open Modal</Button>
|
||||
<Modal open={isOpen} onClose={() => setIsOpen(false)}>
|
||||
Fancy Modal
|
||||
</Modal>
|
||||
</div> */}
|
||||
|
||||
{/* Footer */}
|
||||
<div className="flex w-full h-[250px] items-center text-gray-400">
|
||||
<div className="font-bold ">
|
||||
Email us at
|
||||
<a href="mailto:kevosattire@gmail.com" className="text-emerald-500"> kevosattire@gmail.com</a> to
|
||||
order!
|
||||
<a href="mailto:kevosattire@gmail.com" className="text-emerald-500">
|
||||
kevosattire@gmail.com
|
||||
</a>
|
||||
to order!
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
|
||||
26
frontend/src/components/ClientPortal/ClientPortal.tsx
Normal file
@ -0,0 +1,26 @@
|
||||
//components/ClientPortal.tsx
|
||||
|
||||
import { useEffect, useRef } from "react";
|
||||
import { Poppins } from "next/font/google";
|
||||
import { createPortal } from "react-dom";
|
||||
type ClientPortalInterface = {
|
||||
children: React.ReactNode;
|
||||
show?: boolean;
|
||||
onClose?: () => void;
|
||||
selector: string;
|
||||
};
|
||||
|
||||
const ClientPortal = ({ children, selector, show }: ClientPortalInterface) => {
|
||||
const ref = useRef<Element | null>(null);
|
||||
useEffect(() => {
|
||||
ref.current = document.getElementById(selector);
|
||||
}, [selector]);
|
||||
return show && ref.current ? createPortal(children, ref.current) : null;
|
||||
};
|
||||
|
||||
export default ClientPortal;
|
||||
|
||||
export const poppins = Poppins({
|
||||
weight: ["400", "500", "600", "700"],
|
||||
subsets: ["latin"],
|
||||
});
|
||||
0
frontend/src/components/Modal/Modal.css
Normal file
23
frontend/src/components/Modal/Modal.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
import React from "react";
|
||||
import "./Modal.css";
|
||||
import { Button } from "../ui/button";
|
||||
import ReactDom from 'react-dom';
|
||||
|
||||
// make sure to update index.html with <div id="portal"></div> under <div id="root"></div>
|
||||
|
||||
const Modal = ({ open, onClose, children }: any) => {
|
||||
if (!open) return null;
|
||||
|
||||
return ReactDom.createPortal (
|
||||
<>
|
||||
<div className="fixed top-0 left-0 right-0 bottom-0 bg-slate-900 bg-opacity-70"></div>
|
||||
<div className="fixed top-1/2 left-1/2 bg-[#D7D7D7] p-[50px] z-[1000] translate-x-[-50%] translate-y-[-50%]">
|
||||
<Button onClick={onClose}>Close</Button>
|
||||
{children}
|
||||
</div>
|
||||
</>,
|
||||
document.getElementById('portal')!
|
||||
);
|
||||
};
|
||||
|
||||
export default Modal;
|
||||
@ -4,6 +4,7 @@ import Image from "next/image";
|
||||
import localFont from "next/font/local";
|
||||
import { Inter } from "next/font/google";
|
||||
import { Card } from "../card";
|
||||
import Modal from "../../Modal/Modal";
|
||||
|
||||
const interBold = localFont({
|
||||
src: "./Inter-Bold.woff",
|
||||
@ -15,10 +16,9 @@ const extraBold = localFont({
|
||||
});
|
||||
const inter = Inter({ subsets: ["latin"] });
|
||||
|
||||
|
||||
const MenuCard = ({ Menu }: any) => {
|
||||
return (
|
||||
<div className="grid desktop:grid-cols-5 tablet:grid-cols-3 md:grid-cols-2 grid-cols-1 grid-flow-row gap-y-6 md:gap-x-6 ">
|
||||
<div className="grid qhd:grid-cols-5 desktop:grid-cols-4 tablet:grid-cols-3 md:grid-cols-2 grid-cols-1 grid-flow-row gap-y-6 md:gap-x-6 ">
|
||||
{Menu.map((menu_item: any) => {
|
||||
return (
|
||||
<Card
|
||||
|
||||
55
frontend/src/components/ui/button.tsx
Normal file
@ -0,0 +1,55 @@
|
||||
import * as React from "react"
|
||||
import { Slot } from "@radix-ui/react-slot"
|
||||
import { cva, type VariantProps } from "class-variance-authority"
|
||||
import { cn } from "../../lib/utils"
|
||||
|
||||
const buttonVariants = cva(
|
||||
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
||||
destructive:
|
||||
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
||||
outline:
|
||||
"border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
||||
secondary:
|
||||
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
||||
ghost: "hover:bg-accent hover:text-accent-foreground",
|
||||
link: "text-primary underline-offset-4 hover:underline",
|
||||
},
|
||||
size: {
|
||||
default: "h-10 px-4 py-2",
|
||||
sm: "h-9 rounded-md px-3",
|
||||
lg: "h-11 rounded-md px-8",
|
||||
icon: "h-10 w-10",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
size: "default",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
export interface ButtonProps
|
||||
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
||||
VariantProps<typeof buttonVariants> {
|
||||
asChild?: boolean
|
||||
}
|
||||
|
||||
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
({ className, variant, size, asChild = false, ...props }, ref) => {
|
||||
const Comp = asChild ? Slot : "button"
|
||||
return (
|
||||
<Comp
|
||||
className={cn(buttonVariants({ variant, size, className }))}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
)
|
||||
Button.displayName = "Button"
|
||||
|
||||
export { Button, buttonVariants }
|
||||
114
frontend/src/styles/Home.module.css
Normal file
@ -0,0 +1,114 @@
|
||||
|
||||
.main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 6rem;
|
||||
}
|
||||
|
||||
.removeButton{
|
||||
border: none;
|
||||
background-color: #ffffff;
|
||||
cursor: pointer;
|
||||
padding: 5px 7px;
|
||||
}
|
||||
.removeButton:hover{
|
||||
background-color: rgba(189, 195, 199, 1.0);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
/* Enable hover only on non-touch devices */
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
.card:hover {
|
||||
background: rgba(var(--card-rgb), 0.1);
|
||||
border: 1px solid rgba(var(--card-border-rgb), 0.15);
|
||||
}
|
||||
|
||||
.card:hover span {
|
||||
transform: translateX(4px);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion) {
|
||||
.card:hover span {
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
.modal{
|
||||
background: rgba(255, 255, 255,1.0);
|
||||
width: 60%;
|
||||
max-height: 500px;
|
||||
border-radius: 15px;
|
||||
padding: 20px;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.header{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
border-bottom: 1px solid rgba(189, 195, 199,1.0);
|
||||
}
|
||||
.header h4{
|
||||
color: rgb(17 24 39 0.3);
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 13px;
|
||||
}
|
||||
|
||||
.body{
|
||||
padding-top: 10px;
|
||||
}
|
||||
.body p{
|
||||
color: rgba(116, 125, 140,1.0);
|
||||
font-size: 14px;
|
||||
line-height: 28px;
|
||||
text-align: left;
|
||||
}
|
||||
.overflow{
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
transition: 1;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 8px 18px;
|
||||
cursor: pointer;
|
||||
border: 0px solid rgb(14, 158, 62);
|
||||
border-radius: 3px;
|
||||
color: rgba(255, 255, 255,1.0);
|
||||
font-size: 16px;
|
||||
border-radius: 5px;
|
||||
background: rgb(14, 158, 62);
|
||||
}
|
||||
.btn:hover{
|
||||
background: rgb(9, 99, 39);
|
||||
}
|
||||
|
||||
.groupbtn{
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.cancleBtn{
|
||||
padding: 10px 20px;
|
||||
margin: 0px 10px;
|
||||
cursor: pointer;
|
||||
border: 0px solid rgba(231, 76, 60,1.0);
|
||||
border-radius: 3px;
|
||||
color: rgba(255, 255, 255,1.0);
|
||||
font-size: 16px;
|
||||
border-radius: 5px;
|
||||
background: rgba(231, 76, 60,1.0);
|
||||
}
|
||||
.reactontent {
|
||||
margin: 20px 0px;
|
||||
}
|
||||
@ -53,6 +53,11 @@ const config = {
|
||||
foreground: "hsl(var(--card-foreground))",
|
||||
},
|
||||
},
|
||||
screens: {
|
||||
tablet: "1080px",
|
||||
desktop: "1340px",
|
||||
qhd: "1660px",
|
||||
},
|
||||
borderRadius: {
|
||||
lg: "var(--radius)",
|
||||
md: "calc(var(--radius) - 2px)",
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"@/*": ["./frontend/src/*"]
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||
|
||||