Spaces:
Running
Running
Upload 27 files
Browse files- .bolt/config.json +3 -0
- .gitignore +37 -0
- Dockerfile +30 -0
- backend/__init__.py +1 -0
- backend/__pycache__/main.cpython-312.pyc +0 -0
- backend/main.py +113 -0
- backend/modules/__init__.py +1 -0
- backend/modules/__pycache__/__init__.cpython-312.pyc +0 -0
- backend/modules/__pycache__/document_processor.cpython-312.pyc +0 -0
- backend/modules/__pycache__/image_processor.cpython-312.pyc +0 -0
- backend/modules/document_processor.py +74 -0
- backend/modules/image_processor.py +56 -0
- backend/requirements.txt +7 -0
- counter.js +9 -0
- frontend/css/animations.css +160 -0
- frontend/css/styles.css +519 -0
- frontend/index.html +169 -0
- frontend/js/main.js +132 -0
- frontend/js/results.js +82 -0
- frontend/js/upload.js +261 -0
- index.html +13 -0
- javascript.svg +1 -0
- main.js +24 -0
- package-lock.json +912 -0
- package.json +14 -0
- public/vite.svg +1 -0
- style.css +96 -0
.bolt/config.json
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"template": "vite"
|
3 |
+
}
|
.gitignore
ADDED
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Python
|
2 |
+
__pycache__/
|
3 |
+
*.py[cod]
|
4 |
+
*$py.class
|
5 |
+
*.so
|
6 |
+
.Python
|
7 |
+
env/
|
8 |
+
build/
|
9 |
+
develop-eggs/
|
10 |
+
dist/
|
11 |
+
downloads/
|
12 |
+
eggs/
|
13 |
+
.eggs/
|
14 |
+
lib/
|
15 |
+
lib64/
|
16 |
+
parts/
|
17 |
+
sdist/
|
18 |
+
var/
|
19 |
+
*.egg-info/
|
20 |
+
.installed.cfg
|
21 |
+
*.egg
|
22 |
+
|
23 |
+
# Virtual Environment
|
24 |
+
venv/
|
25 |
+
ENV/
|
26 |
+
env/
|
27 |
+
|
28 |
+
# IDEs and editors
|
29 |
+
.idea/
|
30 |
+
.vscode/
|
31 |
+
*.swp
|
32 |
+
*.swo
|
33 |
+
.DS_Store
|
34 |
+
|
35 |
+
# Project specific
|
36 |
+
uploads/
|
37 |
+
*.log
|
Dockerfile
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
FROM python:3.10-slim
|
2 |
+
|
3 |
+
WORKDIR /app
|
4 |
+
|
5 |
+
# Copy requirements and install dependencies
|
6 |
+
COPY ./backend/requirements.txt /app/
|
7 |
+
RUN pip install --no-cache-dir -r requirements.txt
|
8 |
+
|
9 |
+
# Install additional dependencies for document processing
|
10 |
+
# Note: These would be replaced with actual document processing libraries in production
|
11 |
+
RUN pip install --no-cache-dir pandas openpyxl python-docx
|
12 |
+
|
13 |
+
# Copy backend code
|
14 |
+
COPY ./backend /app/backend
|
15 |
+
|
16 |
+
# Copy frontend files
|
17 |
+
COPY ./frontend /app/frontend
|
18 |
+
|
19 |
+
# Create uploads directory
|
20 |
+
RUN mkdir -p /app/uploads
|
21 |
+
|
22 |
+
# Set environment variables
|
23 |
+
ENV PYTHONPATH=/app
|
24 |
+
ENV PORT=7860
|
25 |
+
|
26 |
+
# Expose the port
|
27 |
+
EXPOSE 7860
|
28 |
+
|
29 |
+
# Run the FastAPI app
|
30 |
+
CMD ["python", "backend/main.py"]
|
backend/__init__.py
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
# Backend package initialization
|
backend/__pycache__/main.cpython-312.pyc
ADDED
Binary file (4.75 kB). View file
|
|
backend/main.py
ADDED
@@ -0,0 +1,113 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from fastapi import FastAPI, File, UploadFile, Form, HTTPException
|
2 |
+
from fastapi.staticfiles import StaticFiles
|
3 |
+
from fastapi.responses import JSONResponse
|
4 |
+
import uvicorn
|
5 |
+
import os
|
6 |
+
from typing import List, Optional
|
7 |
+
import shutil
|
8 |
+
from pathlib import Path
|
9 |
+
import uuid
|
10 |
+
|
11 |
+
# Import AI functionality modules
|
12 |
+
from modules.document_processor import process_document
|
13 |
+
from modules.image_processor import process_image
|
14 |
+
|
15 |
+
# Create FastAPI app
|
16 |
+
app = FastAPI(title="AI Document Analysis API")
|
17 |
+
|
18 |
+
# Create upload directory if it doesn't exist
|
19 |
+
UPLOAD_DIR = Path("uploads")
|
20 |
+
UPLOAD_DIR.mkdir(exist_ok=True)
|
21 |
+
|
22 |
+
# Mount static files - updated path to be relative to the current directory
|
23 |
+
app.mount("/static", StaticFiles(directory="frontend"), name="static")
|
24 |
+
|
25 |
+
@app.get("/")
|
26 |
+
def read_root():
|
27 |
+
return {"message": "AI Document Analysis API is running"}
|
28 |
+
|
29 |
+
@app.post("/api/analyze-document")
|
30 |
+
async def analyze_document(
|
31 |
+
file: UploadFile = File(...),
|
32 |
+
analysis_type: str = Form(...)
|
33 |
+
):
|
34 |
+
# Validate file type
|
35 |
+
allowed_extensions = [".pdf", ".docx", ".pptx", ".xlsx", ".xls"]
|
36 |
+
file_ext = os.path.splitext(file.filename)[1].lower()
|
37 |
+
|
38 |
+
if file_ext not in allowed_extensions:
|
39 |
+
raise HTTPException(status_code=400, detail=f"File type not supported. Allowed types: {', '.join(allowed_extensions)}")
|
40 |
+
|
41 |
+
# Create unique filename
|
42 |
+
unique_filename = f"{uuid.uuid4()}{file_ext}"
|
43 |
+
file_path = UPLOAD_DIR / unique_filename
|
44 |
+
|
45 |
+
# Save uploaded file
|
46 |
+
with open(file_path, "wb") as buffer:
|
47 |
+
shutil.copyfileobj(file.file, buffer)
|
48 |
+
|
49 |
+
try:
|
50 |
+
# Process document based on analysis type
|
51 |
+
if analysis_type == "summarize":
|
52 |
+
result = process_document(str(file_path), "summarize")
|
53 |
+
else:
|
54 |
+
raise HTTPException(status_code=400, detail="Invalid analysis type")
|
55 |
+
|
56 |
+
# Return results
|
57 |
+
return {
|
58 |
+
"filename": file.filename,
|
59 |
+
"analysis_type": analysis_type,
|
60 |
+
"result": result
|
61 |
+
}
|
62 |
+
except Exception as e:
|
63 |
+
# Clean up file on error
|
64 |
+
if file_path.exists():
|
65 |
+
os.remove(file_path)
|
66 |
+
raise HTTPException(status_code=500, detail=str(e))
|
67 |
+
|
68 |
+
@app.post("/api/analyze-image")
|
69 |
+
async def analyze_image(
|
70 |
+
file: UploadFile = File(...),
|
71 |
+
analysis_type: str = Form(...)
|
72 |
+
):
|
73 |
+
# Validate file type
|
74 |
+
allowed_extensions = [".jpg", ".jpeg", ".png"]
|
75 |
+
file_ext = os.path.splitext(file.filename)[1].lower()
|
76 |
+
|
77 |
+
if file_ext not in allowed_extensions:
|
78 |
+
raise HTTPException(status_code=400, detail=f"File type not supported. Allowed types: {', '.join(allowed_extensions)}")
|
79 |
+
|
80 |
+
# Create unique filename
|
81 |
+
unique_filename = f"{uuid.uuid4()}{file_ext}"
|
82 |
+
file_path = UPLOAD_DIR / unique_filename
|
83 |
+
|
84 |
+
# Save uploaded file
|
85 |
+
with open(file_path, "wb") as buffer:
|
86 |
+
shutil.copyfileobj(file.file, buffer)
|
87 |
+
|
88 |
+
try:
|
89 |
+
# Process image based on analysis type
|
90 |
+
if analysis_type == "caption":
|
91 |
+
result = process_image(str(file_path), "caption")
|
92 |
+
else:
|
93 |
+
raise HTTPException(status_code=400, detail="Invalid analysis type")
|
94 |
+
|
95 |
+
# Return results
|
96 |
+
return {
|
97 |
+
"filename": file.filename,
|
98 |
+
"analysis_type": analysis_type,
|
99 |
+
"result": result
|
100 |
+
}
|
101 |
+
except Exception as e:
|
102 |
+
# Clean up file on error
|
103 |
+
if file_path.exists():
|
104 |
+
os.remove(file_path)
|
105 |
+
raise HTTPException(status_code=500, detail=str(e))
|
106 |
+
|
107 |
+
# Add health check endpoint
|
108 |
+
@app.get("/health")
|
109 |
+
def health_check():
|
110 |
+
return {"status": "healthy"}
|
111 |
+
|
112 |
+
if __name__ == "__main__":
|
113 |
+
uvicorn.run("main:app", host="0.0.0.0", port=7860, reload=True)
|
backend/modules/__init__.py
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
# Modules package initialization
|
backend/modules/__pycache__/__init__.cpython-312.pyc
ADDED
Binary file (168 Bytes). View file
|
|
backend/modules/__pycache__/document_processor.cpython-312.pyc
ADDED
Binary file (2.76 kB). View file
|
|
backend/modules/__pycache__/image_processor.cpython-312.pyc
ADDED
Binary file (2.2 kB). View file
|
|
backend/modules/document_processor.py
ADDED
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
from pathlib import Path
|
3 |
+
import tempfile
|
4 |
+
import logging
|
5 |
+
|
6 |
+
# Configure logging
|
7 |
+
logging.basicConfig(level=logging.INFO)
|
8 |
+
logger = logging.getLogger(__name__)
|
9 |
+
|
10 |
+
# This is a placeholder for actual Hugging Face model integration
|
11 |
+
# In a real implementation, you would import and use appropriate models
|
12 |
+
def process_document(file_path, analysis_type):
|
13 |
+
"""
|
14 |
+
Process a document using Hugging Face models.
|
15 |
+
|
16 |
+
Args:
|
17 |
+
file_path (str): Path to the uploaded document
|
18 |
+
analysis_type (str): Type of analysis to perform (summarize, etc.)
|
19 |
+
|
20 |
+
Returns:
|
21 |
+
str: Result of document analysis
|
22 |
+
"""
|
23 |
+
logger.info(f"Processing document: {file_path} with analysis type: {analysis_type}")
|
24 |
+
|
25 |
+
# Get file extension
|
26 |
+
file_ext = os.path.splitext(file_path)[1].lower()
|
27 |
+
|
28 |
+
# Extract text from document based on file type
|
29 |
+
extracted_text = extract_text_from_document(file_path, file_ext)
|
30 |
+
|
31 |
+
# For demonstration purposes, return a mock summary
|
32 |
+
# In a real implementation, you would use a Hugging Face model here
|
33 |
+
if analysis_type == "summarize":
|
34 |
+
# Mock summarization result
|
35 |
+
summary = f"This is a mock summary of the document. In a real implementation, this would be generated by a Hugging Face model like Llama-2-70b-chat-hf or similar.\n\nThe document appears to contain information about {get_mock_topic(extracted_text)}."
|
36 |
+
return summary
|
37 |
+
else:
|
38 |
+
return "Unsupported analysis type"
|
39 |
+
|
40 |
+
def extract_text_from_document(file_path, file_ext):
|
41 |
+
"""
|
42 |
+
Extract text from different document types.
|
43 |
+
|
44 |
+
This is a placeholder that would be replaced with actual document parsing
|
45 |
+
libraries like Apache Tika, PyMuPDF, etc.
|
46 |
+
"""
|
47 |
+
logger.info(f"Extracting text from {file_path}")
|
48 |
+
|
49 |
+
# In a real implementation, you would use libraries like:
|
50 |
+
# - PyMuPDF for PDFs
|
51 |
+
# - python-docx for DOCX files
|
52 |
+
# - python-pptx for PPTX files
|
53 |
+
# - openpyxl for Excel files
|
54 |
+
|
55 |
+
# Mock extraction based on file type
|
56 |
+
if file_ext == ".pdf":
|
57 |
+
return "This is mock extracted text from a PDF document."
|
58 |
+
elif file_ext == ".docx":
|
59 |
+
return "This is mock extracted text from a Word document."
|
60 |
+
elif file_ext == ".pptx":
|
61 |
+
return "This is mock extracted text from a PowerPoint presentation."
|
62 |
+
elif file_ext in [".xlsx", ".xls"]:
|
63 |
+
return "This is mock extracted tabular data from an Excel spreadsheet."
|
64 |
+
else:
|
65 |
+
return "Unknown document type"
|
66 |
+
|
67 |
+
def get_mock_topic(text):
|
68 |
+
"""Generate a mock topic based on some simple heuristics."""
|
69 |
+
# In a real implementation, this might use keyword extraction or topic modeling
|
70 |
+
topics = ["business analysis", "scientific research", "financial data",
|
71 |
+
"project planning", "educational material"]
|
72 |
+
|
73 |
+
# Simple mock topic selection based on text length
|
74 |
+
return topics[len(text) % len(topics)]
|
backend/modules/image_processor.py
ADDED
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import logging
|
3 |
+
from pathlib import Path
|
4 |
+
|
5 |
+
# Configure logging
|
6 |
+
logging.basicConfig(level=logging.INFO)
|
7 |
+
logger = logging.getLogger(__name__)
|
8 |
+
|
9 |
+
# This is a placeholder for actual Hugging Face model integration
|
10 |
+
# In a real implementation, you would import and use appropriate models
|
11 |
+
def process_image(file_path, analysis_type):
|
12 |
+
"""
|
13 |
+
Process an image using Hugging Face models.
|
14 |
+
|
15 |
+
Args:
|
16 |
+
file_path (str): Path to the uploaded image
|
17 |
+
analysis_type (str): Type of analysis to perform (caption, etc.)
|
18 |
+
|
19 |
+
Returns:
|
20 |
+
str: Result of image analysis
|
21 |
+
"""
|
22 |
+
logger.info(f"Processing image: {file_path} with analysis type: {analysis_type}")
|
23 |
+
|
24 |
+
# For demonstration purposes, return a mock caption
|
25 |
+
# In a real implementation, you would use a Hugging Face model here
|
26 |
+
if analysis_type == "caption":
|
27 |
+
# Mock image captioning result
|
28 |
+
caption = generate_mock_caption(file_path)
|
29 |
+
return caption
|
30 |
+
else:
|
31 |
+
return "Unsupported analysis type"
|
32 |
+
|
33 |
+
def generate_mock_caption(image_path):
|
34 |
+
"""
|
35 |
+
Generate a mock image caption.
|
36 |
+
|
37 |
+
In a real implementation, this would use a Hugging Face model like
|
38 |
+
Qwen/Qwen2.5-VL-7B-Instruct or similar for image captioning.
|
39 |
+
"""
|
40 |
+
# Get file size as a simple way to generate different captions
|
41 |
+
file_size = os.path.getsize(image_path)
|
42 |
+
|
43 |
+
# List of mock captions
|
44 |
+
captions = [
|
45 |
+
"A beautiful landscape with mountains and a lake under blue sky.",
|
46 |
+
"A person working at a desk with a computer and various office supplies.",
|
47 |
+
"A busy city street with pedestrians and vehicles during the day.",
|
48 |
+
"A close-up photograph of a flower with vibrant colors and intricate details.",
|
49 |
+
"A group of people gathered around a table for what appears to be a business meeting.",
|
50 |
+
"A modern architectural building with glass and steel elements."
|
51 |
+
]
|
52 |
+
|
53 |
+
# Select a caption based on file size
|
54 |
+
mock_caption = captions[file_size % len(captions)]
|
55 |
+
|
56 |
+
return f"{mock_caption}\n\nNote: This is a mock caption. In a real implementation, this would be generated by a vision-language model like Qwen/Qwen2.5-VL-7B-Instruct."
|
backend/requirements.txt
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
fastapi==0.104.1
|
2 |
+
uvicorn==0.23.2
|
3 |
+
python-multipart==0.0.6
|
4 |
+
aiofiles==23.2.1
|
5 |
+
Pillow==10.0.1
|
6 |
+
pydantic==2.4.2
|
7 |
+
python-dotenv==1.0.0
|
counter.js
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
export function setupCounter(element) {
|
2 |
+
let counter = 0
|
3 |
+
const setCounter = (count) => {
|
4 |
+
counter = count
|
5 |
+
element.innerHTML = `count is ${counter}`
|
6 |
+
}
|
7 |
+
element.addEventListener('click', () => setCounter(counter + 1))
|
8 |
+
setCounter(0)
|
9 |
+
}
|
frontend/css/animations.css
ADDED
@@ -0,0 +1,160 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* Animations */
|
2 |
+
|
3 |
+
/* Spinner Animation */
|
4 |
+
@keyframes spin {
|
5 |
+
0% { transform: rotate(0deg); }
|
6 |
+
100% { transform: rotate(360deg); }
|
7 |
+
}
|
8 |
+
|
9 |
+
.spinner {
|
10 |
+
animation: spin 1s linear infinite;
|
11 |
+
}
|
12 |
+
|
13 |
+
/* Fade In Animation */
|
14 |
+
@keyframes fadeIn {
|
15 |
+
from { opacity: 0; }
|
16 |
+
to { opacity: 1; }
|
17 |
+
}
|
18 |
+
|
19 |
+
.fade-in {
|
20 |
+
animation: fadeIn 0.5s ease-in;
|
21 |
+
}
|
22 |
+
|
23 |
+
/* Slide Up Animation */
|
24 |
+
@keyframes slideUp {
|
25 |
+
from {
|
26 |
+
transform: translateY(20px);
|
27 |
+
opacity: 0;
|
28 |
+
}
|
29 |
+
to {
|
30 |
+
transform: translateY(0);
|
31 |
+
opacity: 1;
|
32 |
+
}
|
33 |
+
}
|
34 |
+
|
35 |
+
.slide-up {
|
36 |
+
animation: slideUp 0.5s ease-out;
|
37 |
+
}
|
38 |
+
|
39 |
+
/* Pulse Animation */
|
40 |
+
@keyframes pulse {
|
41 |
+
0% { transform: scale(1); }
|
42 |
+
50% { transform: scale(1.05); }
|
43 |
+
100% { transform: scale(1); }
|
44 |
+
}
|
45 |
+
|
46 |
+
.pulse {
|
47 |
+
animation: pulse 2s infinite;
|
48 |
+
}
|
49 |
+
|
50 |
+
/* Scale Animation */
|
51 |
+
@keyframes scale {
|
52 |
+
from { transform: scale(0.95); }
|
53 |
+
to { transform: scale(1); }
|
54 |
+
}
|
55 |
+
|
56 |
+
.scale {
|
57 |
+
animation: scale 0.3s ease-out;
|
58 |
+
}
|
59 |
+
|
60 |
+
/* Button Hover Effects */
|
61 |
+
.analyze-btn:not(:disabled):hover {
|
62 |
+
transform: translateY(-2px);
|
63 |
+
box-shadow: 0 4px 6px rgba(37, 99, 235, 0.25);
|
64 |
+
}
|
65 |
+
|
66 |
+
.analyze-btn:not(:disabled):active {
|
67 |
+
transform: translateY(0);
|
68 |
+
}
|
69 |
+
|
70 |
+
/* Card Hover Effects */
|
71 |
+
.feature-card:hover .feature-icon {
|
72 |
+
transform: scale(1.1);
|
73 |
+
background-color: rgba(37, 99, 235, 0.15);
|
74 |
+
}
|
75 |
+
|
76 |
+
/* File Upload Animation */
|
77 |
+
.upload-area.dragover {
|
78 |
+
transform: scale(1.02);
|
79 |
+
}
|
80 |
+
|
81 |
+
/* Tab Button Animation */
|
82 |
+
.tab-btn {
|
83 |
+
transition: background-color 0.3s ease, color 0.3s ease, border-color 0.3s ease, transform 0.2s ease;
|
84 |
+
}
|
85 |
+
|
86 |
+
.tab-btn:hover:not(.active) {
|
87 |
+
transform: translateY(-2px);
|
88 |
+
}
|
89 |
+
|
90 |
+
.tab-btn.active {
|
91 |
+
transform: translateY(-3px);
|
92 |
+
}
|
93 |
+
|
94 |
+
/* Results Container Animation */
|
95 |
+
.results-container {
|
96 |
+
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
97 |
+
}
|
98 |
+
|
99 |
+
.results-container:hover {
|
100 |
+
box-shadow: var(--shadow-lg);
|
101 |
+
}
|
102 |
+
|
103 |
+
/* Section Transitions */
|
104 |
+
.section-title,
|
105 |
+
.feature-card,
|
106 |
+
.about-content p {
|
107 |
+
opacity: 0;
|
108 |
+
transform: translateY(20px);
|
109 |
+
transition: opacity 0.5s ease, transform 0.5s ease;
|
110 |
+
}
|
111 |
+
|
112 |
+
/* These will be activated by JavaScript when elements come into view */
|
113 |
+
.appear {
|
114 |
+
opacity: 1;
|
115 |
+
transform: translateY(0);
|
116 |
+
}
|
117 |
+
|
118 |
+
/* Hero Section Animation */
|
119 |
+
.hero {
|
120 |
+
background-size: 200% 200%;
|
121 |
+
animation: gradientAnimation 15s ease infinite;
|
122 |
+
}
|
123 |
+
|
124 |
+
@keyframes gradientAnimation {
|
125 |
+
0% { background-position: 0% 50%; }
|
126 |
+
50% { background-position: 100% 50%; }
|
127 |
+
100% { background-position: 0% 50%; }
|
128 |
+
}
|
129 |
+
|
130 |
+
/* Logo Animation */
|
131 |
+
.logo i {
|
132 |
+
transition: transform 0.3s ease;
|
133 |
+
}
|
134 |
+
|
135 |
+
.logo:hover i {
|
136 |
+
transform: rotate(15deg);
|
137 |
+
}
|
138 |
+
|
139 |
+
/* Action Buttons Animation */
|
140 |
+
.action-btn {
|
141 |
+
transition: all 0.2s ease;
|
142 |
+
}
|
143 |
+
|
144 |
+
.action-btn:hover {
|
145 |
+
transform: translateY(-2px);
|
146 |
+
}
|
147 |
+
|
148 |
+
.action-btn:active {
|
149 |
+
transform: translateY(0);
|
150 |
+
}
|
151 |
+
|
152 |
+
/* File Selected Animation */
|
153 |
+
.file-selected {
|
154 |
+
border-color: var(--success-color) !important;
|
155 |
+
background-color: rgba(16, 185, 129, 0.05) !important;
|
156 |
+
}
|
157 |
+
|
158 |
+
.file-selected i {
|
159 |
+
color: var(--success-color);
|
160 |
+
}
|
frontend/css/styles.css
ADDED
@@ -0,0 +1,519 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
:root {
|
2 |
+
--primary-color: #2563EB;
|
3 |
+
--primary-light: #3B82F6;
|
4 |
+
--primary-dark: #1D4ED8;
|
5 |
+
--accent-color: #7C3AED;
|
6 |
+
--accent-light: #8B5CF6;
|
7 |
+
--success-color: #10B981;
|
8 |
+
--warning-color: #F59E0B;
|
9 |
+
--error-color: #EF4444;
|
10 |
+
--text-dark: #1F2937;
|
11 |
+
--text-medium: #4B5563;
|
12 |
+
--text-light: #9CA3AF;
|
13 |
+
--background-color: #F9FAFB;
|
14 |
+
--card-bg: #FFFFFF;
|
15 |
+
--border-color: #E5E7EB;
|
16 |
+
--spacing-xs: 4px;
|
17 |
+
--spacing-sm: 8px;
|
18 |
+
--spacing-md: 16px;
|
19 |
+
--spacing-lg: 24px;
|
20 |
+
--spacing-xl: 32px;
|
21 |
+
--spacing-xxl: 48px;
|
22 |
+
--border-radius-sm: 4px;
|
23 |
+
--border-radius-md: 8px;
|
24 |
+
--border-radius-lg: 12px;
|
25 |
+
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
|
26 |
+
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
27 |
+
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
28 |
+
--font-family: 'Inter', sans-serif;
|
29 |
+
}
|
30 |
+
|
31 |
+
/* Base Styles */
|
32 |
+
* {
|
33 |
+
margin: 0;
|
34 |
+
padding: 0;
|
35 |
+
box-sizing: border-box;
|
36 |
+
}
|
37 |
+
|
38 |
+
html {
|
39 |
+
scroll-behavior: smooth;
|
40 |
+
}
|
41 |
+
|
42 |
+
body {
|
43 |
+
font-family: var(--font-family);
|
44 |
+
line-height: 1.5;
|
45 |
+
color: var(--text-dark);
|
46 |
+
background-color: var(--background-color);
|
47 |
+
}
|
48 |
+
|
49 |
+
.container {
|
50 |
+
width: 100%;
|
51 |
+
max-width: 1200px;
|
52 |
+
margin: 0 auto;
|
53 |
+
padding: 0 var(--spacing-md);
|
54 |
+
}
|
55 |
+
|
56 |
+
/* Typography */
|
57 |
+
h1, h2, h3, h4, h5, h6 {
|
58 |
+
font-weight: 600;
|
59 |
+
line-height: 1.2;
|
60 |
+
margin-bottom: var(--spacing-md);
|
61 |
+
}
|
62 |
+
|
63 |
+
h1 {
|
64 |
+
font-size: 2.5rem;
|
65 |
+
}
|
66 |
+
|
67 |
+
h2 {
|
68 |
+
font-size: 2rem;
|
69 |
+
}
|
70 |
+
|
71 |
+
h3 {
|
72 |
+
font-size: 1.5rem;
|
73 |
+
}
|
74 |
+
|
75 |
+
p {
|
76 |
+
margin-bottom: var(--spacing-md);
|
77 |
+
}
|
78 |
+
|
79 |
+
a {
|
80 |
+
color: var(--primary-color);
|
81 |
+
text-decoration: none;
|
82 |
+
transition: color 0.3s ease;
|
83 |
+
}
|
84 |
+
|
85 |
+
a:hover {
|
86 |
+
color: var(--primary-dark);
|
87 |
+
}
|
88 |
+
|
89 |
+
/* Button Styles */
|
90 |
+
button {
|
91 |
+
cursor: pointer;
|
92 |
+
font-family: var(--font-family);
|
93 |
+
font-size: 1rem;
|
94 |
+
border: none;
|
95 |
+
transition: all 0.3s ease;
|
96 |
+
}
|
97 |
+
|
98 |
+
.btn, .analyze-btn, .action-btn {
|
99 |
+
display: inline-flex;
|
100 |
+
align-items: center;
|
101 |
+
justify-content: center;
|
102 |
+
padding: var(--spacing-sm) var(--spacing-lg);
|
103 |
+
border-radius: var(--border-radius-md);
|
104 |
+
font-weight: 500;
|
105 |
+
}
|
106 |
+
|
107 |
+
.analyze-btn {
|
108 |
+
background-color: var(--primary-color);
|
109 |
+
color: white;
|
110 |
+
font-weight: 600;
|
111 |
+
padding: var(--spacing-md) var(--spacing-xl);
|
112 |
+
border-radius: var(--border-radius-md);
|
113 |
+
margin-top: var(--spacing-md);
|
114 |
+
width: 100%;
|
115 |
+
}
|
116 |
+
|
117 |
+
.analyze-btn:hover {
|
118 |
+
background-color: var(--primary-dark);
|
119 |
+
transform: translateY(-1px);
|
120 |
+
}
|
121 |
+
|
122 |
+
.analyze-btn:disabled {
|
123 |
+
background-color: var(--text-light);
|
124 |
+
cursor: not-allowed;
|
125 |
+
transform: none;
|
126 |
+
}
|
127 |
+
|
128 |
+
.action-btn {
|
129 |
+
padding: var(--spacing-sm) var(--spacing-md);
|
130 |
+
background-color: var(--card-bg);
|
131 |
+
color: var(--text-medium);
|
132 |
+
border: 1px solid var(--border-color);
|
133 |
+
margin-left: var(--spacing-sm);
|
134 |
+
}
|
135 |
+
|
136 |
+
.action-btn:hover {
|
137 |
+
background-color: var(--background-color);
|
138 |
+
color: var(--text-dark);
|
139 |
+
}
|
140 |
+
|
141 |
+
.action-btn i {
|
142 |
+
margin-right: 4px;
|
143 |
+
}
|
144 |
+
|
145 |
+
/* Header */
|
146 |
+
.header {
|
147 |
+
background-color: var(--card-bg);
|
148 |
+
box-shadow: var(--shadow-sm);
|
149 |
+
position: sticky;
|
150 |
+
top: 0;
|
151 |
+
z-index: 100;
|
152 |
+
}
|
153 |
+
|
154 |
+
.header .container {
|
155 |
+
display: flex;
|
156 |
+
align-items: center;
|
157 |
+
justify-content: space-between;
|
158 |
+
padding-top: var(--spacing-md);
|
159 |
+
padding-bottom: var(--spacing-md);
|
160 |
+
}
|
161 |
+
|
162 |
+
.logo {
|
163 |
+
display: flex;
|
164 |
+
align-items: center;
|
165 |
+
}
|
166 |
+
|
167 |
+
.logo i {
|
168 |
+
font-size: 1.8rem;
|
169 |
+
color: var(--primary-color);
|
170 |
+
margin-right: var(--spacing-sm);
|
171 |
+
}
|
172 |
+
|
173 |
+
.logo h1 {
|
174 |
+
font-size: 1.5rem;
|
175 |
+
font-weight: 700;
|
176 |
+
margin-bottom: 0;
|
177 |
+
}
|
178 |
+
|
179 |
+
.nav ul {
|
180 |
+
display: flex;
|
181 |
+
list-style: none;
|
182 |
+
}
|
183 |
+
|
184 |
+
.nav li {
|
185 |
+
margin-left: var(--spacing-lg);
|
186 |
+
}
|
187 |
+
|
188 |
+
.nav a {
|
189 |
+
color: var(--text-medium);
|
190 |
+
font-weight: 500;
|
191 |
+
padding: 0.5rem 0;
|
192 |
+
position: relative;
|
193 |
+
}
|
194 |
+
|
195 |
+
.nav a.active, .nav a:hover {
|
196 |
+
color: var(--primary-color);
|
197 |
+
}
|
198 |
+
|
199 |
+
.nav a.active::after, .nav a:hover::after {
|
200 |
+
content: '';
|
201 |
+
position: absolute;
|
202 |
+
bottom: -4px;
|
203 |
+
left: 0;
|
204 |
+
width: 100%;
|
205 |
+
height: 2px;
|
206 |
+
background-color: var(--primary-color);
|
207 |
+
}
|
208 |
+
|
209 |
+
/* Hero Section */
|
210 |
+
.hero {
|
211 |
+
padding: var(--spacing-xxl) 0;
|
212 |
+
text-align: center;
|
213 |
+
background: linear-gradient(120deg, var(--primary-light), var(--accent-color));
|
214 |
+
color: white;
|
215 |
+
}
|
216 |
+
|
217 |
+
.hero-title {
|
218 |
+
font-size: 3rem;
|
219 |
+
font-weight: 700;
|
220 |
+
margin-bottom: var(--spacing-md);
|
221 |
+
}
|
222 |
+
|
223 |
+
.hero-subtitle {
|
224 |
+
font-size: 1.2rem;
|
225 |
+
max-width: 800px;
|
226 |
+
margin: 0 auto var(--spacing-lg);
|
227 |
+
}
|
228 |
+
|
229 |
+
/* Upload Section */
|
230 |
+
.upload-section {
|
231 |
+
padding: var(--spacing-xxl) 0;
|
232 |
+
}
|
233 |
+
|
234 |
+
.tabs {
|
235 |
+
display: flex;
|
236 |
+
justify-content: center;
|
237 |
+
margin-bottom: var(--spacing-xl);
|
238 |
+
}
|
239 |
+
|
240 |
+
.tab-btn {
|
241 |
+
padding: var(--spacing-md) var(--spacing-xl);
|
242 |
+
background-color: var(--card-bg);
|
243 |
+
color: var(--text-medium);
|
244 |
+
border: 1px solid var(--border-color);
|
245 |
+
font-weight: 500;
|
246 |
+
}
|
247 |
+
|
248 |
+
.tab-btn:first-child {
|
249 |
+
border-radius: var(--border-radius-md) 0 0 var(--border-radius-md);
|
250 |
+
}
|
251 |
+
|
252 |
+
.tab-btn:last-child {
|
253 |
+
border-radius: 0 var(--border-radius-md) var(--border-radius-md) 0;
|
254 |
+
}
|
255 |
+
|
256 |
+
.tab-btn.active {
|
257 |
+
background-color: var(--primary-color);
|
258 |
+
color: white;
|
259 |
+
border-color: var(--primary-color);
|
260 |
+
}
|
261 |
+
|
262 |
+
.tab-content {
|
263 |
+
display: none;
|
264 |
+
}
|
265 |
+
|
266 |
+
.tab-content.active {
|
267 |
+
display: block;
|
268 |
+
}
|
269 |
+
|
270 |
+
.upload-container {
|
271 |
+
display: grid;
|
272 |
+
grid-template-columns: 1fr;
|
273 |
+
gap: var(--spacing-xl);
|
274 |
+
}
|
275 |
+
|
276 |
+
@media (min-width: 768px) {
|
277 |
+
.upload-container {
|
278 |
+
grid-template-columns: 2fr 1fr;
|
279 |
+
}
|
280 |
+
}
|
281 |
+
|
282 |
+
.upload-area {
|
283 |
+
display: flex;
|
284 |
+
flex-direction: column;
|
285 |
+
align-items: center;
|
286 |
+
justify-content: center;
|
287 |
+
text-align: center;
|
288 |
+
padding: var(--spacing-xxl);
|
289 |
+
background-color: var(--card-bg);
|
290 |
+
border: 2px dashed var(--border-color);
|
291 |
+
border-radius: var(--border-radius-lg);
|
292 |
+
cursor: pointer;
|
293 |
+
transition: all 0.3s ease;
|
294 |
+
}
|
295 |
+
|
296 |
+
.upload-area:hover {
|
297 |
+
border-color: var(--primary-light);
|
298 |
+
background-color: rgba(37, 99, 235, 0.05);
|
299 |
+
}
|
300 |
+
|
301 |
+
.upload-area.dragover {
|
302 |
+
border-color: var(--primary-color);
|
303 |
+
background-color: rgba(37, 99, 235, 0.1);
|
304 |
+
}
|
305 |
+
|
306 |
+
.upload-area i {
|
307 |
+
font-size: 3rem;
|
308 |
+
color: var(--primary-color);
|
309 |
+
margin-bottom: var(--spacing-md);
|
310 |
+
}
|
311 |
+
|
312 |
+
.upload-area h3 {
|
313 |
+
margin-bottom: var(--spacing-sm);
|
314 |
+
}
|
315 |
+
|
316 |
+
.upload-area .file-types {
|
317 |
+
font-size: 0.9rem;
|
318 |
+
color: var(--text-light);
|
319 |
+
margin-top: var(--spacing-md);
|
320 |
+
}
|
321 |
+
|
322 |
+
.analysis-options {
|
323 |
+
background-color: var(--card-bg);
|
324 |
+
padding: var(--spacing-xl);
|
325 |
+
border-radius: var(--border-radius-lg);
|
326 |
+
box-shadow: var(--shadow-md);
|
327 |
+
}
|
328 |
+
|
329 |
+
.radio-group {
|
330 |
+
margin-bottom: var(--spacing-lg);
|
331 |
+
}
|
332 |
+
|
333 |
+
.radio-option {
|
334 |
+
margin-bottom: var(--spacing-sm);
|
335 |
+
display: flex;
|
336 |
+
align-items: center;
|
337 |
+
}
|
338 |
+
|
339 |
+
.radio-option input[type="radio"] {
|
340 |
+
margin-right: var(--spacing-sm);
|
341 |
+
}
|
342 |
+
|
343 |
+
/* Results Container */
|
344 |
+
.results-container {
|
345 |
+
margin-top: var(--spacing-xl);
|
346 |
+
background-color: var(--card-bg);
|
347 |
+
border-radius: var(--border-radius-lg);
|
348 |
+
box-shadow: var(--shadow-md);
|
349 |
+
overflow: hidden;
|
350 |
+
}
|
351 |
+
|
352 |
+
.results-header {
|
353 |
+
display: flex;
|
354 |
+
justify-content: space-between;
|
355 |
+
align-items: center;
|
356 |
+
padding: var(--spacing-lg);
|
357 |
+
border-bottom: 1px solid var(--border-color);
|
358 |
+
}
|
359 |
+
|
360 |
+
.results-header h2 {
|
361 |
+
margin-bottom: 0;
|
362 |
+
}
|
363 |
+
|
364 |
+
.results-content {
|
365 |
+
padding: var(--spacing-xl);
|
366 |
+
white-space: pre-wrap;
|
367 |
+
line-height: 1.6;
|
368 |
+
}
|
369 |
+
|
370 |
+
/* Features Section */
|
371 |
+
.features {
|
372 |
+
padding: var(--spacing-xxl) 0;
|
373 |
+
background-color: var(--card-bg);
|
374 |
+
}
|
375 |
+
|
376 |
+
.section-title {
|
377 |
+
text-align: center;
|
378 |
+
margin-bottom: var(--spacing-xl);
|
379 |
+
}
|
380 |
+
|
381 |
+
.features-grid {
|
382 |
+
display: grid;
|
383 |
+
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
384 |
+
gap: var(--spacing-xl);
|
385 |
+
}
|
386 |
+
|
387 |
+
.feature-card {
|
388 |
+
background-color: var(--background-color);
|
389 |
+
padding: var(--spacing-xl);
|
390 |
+
border-radius: var(--border-radius-lg);
|
391 |
+
text-align: center;
|
392 |
+
box-shadow: var(--shadow-sm);
|
393 |
+
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
394 |
+
}
|
395 |
+
|
396 |
+
.feature-card:hover {
|
397 |
+
transform: translateY(-5px);
|
398 |
+
box-shadow: var(--shadow-lg);
|
399 |
+
}
|
400 |
+
|
401 |
+
.feature-icon {
|
402 |
+
display: inline-flex;
|
403 |
+
align-items: center;
|
404 |
+
justify-content: center;
|
405 |
+
width: 64px;
|
406 |
+
height: 64px;
|
407 |
+
background-color: rgba(37, 99, 235, 0.1);
|
408 |
+
border-radius: 50%;
|
409 |
+
margin-bottom: var(--spacing-md);
|
410 |
+
}
|
411 |
+
|
412 |
+
.feature-icon i {
|
413 |
+
font-size: 1.5rem;
|
414 |
+
color: var(--primary-color);
|
415 |
+
}
|
416 |
+
|
417 |
+
/* About Section */
|
418 |
+
.about {
|
419 |
+
padding: var(--spacing-xxl) 0;
|
420 |
+
}
|
421 |
+
|
422 |
+
.about-content {
|
423 |
+
max-width: 800px;
|
424 |
+
margin: 0 auto;
|
425 |
+
}
|
426 |
+
|
427 |
+
/* Footer */
|
428 |
+
.footer {
|
429 |
+
background-color: var(--text-dark);
|
430 |
+
color: white;
|
431 |
+
padding: var(--spacing-xl) 0;
|
432 |
+
text-align: center;
|
433 |
+
}
|
434 |
+
|
435 |
+
.footer p {
|
436 |
+
margin-bottom: 0;
|
437 |
+
}
|
438 |
+
|
439 |
+
.footer i {
|
440 |
+
color: var(--error-color);
|
441 |
+
}
|
442 |
+
|
443 |
+
/* Loading Overlay */
|
444 |
+
.loading-overlay {
|
445 |
+
position: fixed;
|
446 |
+
top: 0;
|
447 |
+
left: 0;
|
448 |
+
width: 100%;
|
449 |
+
height: 100%;
|
450 |
+
background-color: rgba(0, 0, 0, 0.7);
|
451 |
+
display: flex;
|
452 |
+
flex-direction: column;
|
453 |
+
align-items: center;
|
454 |
+
justify-content: center;
|
455 |
+
z-index: 1000;
|
456 |
+
color: white;
|
457 |
+
display: none;
|
458 |
+
}
|
459 |
+
|
460 |
+
.spinner {
|
461 |
+
width: 50px;
|
462 |
+
height: 50px;
|
463 |
+
border: 5px solid rgba(255, 255, 255, 0.3);
|
464 |
+
border-radius: 50%;
|
465 |
+
border-top-color: var(--primary-color);
|
466 |
+
margin-bottom: var(--spacing-md);
|
467 |
+
}
|
468 |
+
|
469 |
+
/* Responsive Styles */
|
470 |
+
@media (max-width: 768px) {
|
471 |
+
.hero-title {
|
472 |
+
font-size: 2.2rem;
|
473 |
+
}
|
474 |
+
|
475 |
+
.hero-subtitle {
|
476 |
+
font-size: 1rem;
|
477 |
+
}
|
478 |
+
|
479 |
+
.logo h1 {
|
480 |
+
font-size: 1.2rem;
|
481 |
+
}
|
482 |
+
|
483 |
+
.nav li {
|
484 |
+
margin-left: var(--spacing-md);
|
485 |
+
}
|
486 |
+
|
487 |
+
.upload-area {
|
488 |
+
padding: var(--spacing-lg);
|
489 |
+
}
|
490 |
+
|
491 |
+
.feature-card {
|
492 |
+
padding: var(--spacing-lg);
|
493 |
+
}
|
494 |
+
}
|
495 |
+
|
496 |
+
@media (max-width: 576px) {
|
497 |
+
.logo h1 {
|
498 |
+
display: none;
|
499 |
+
}
|
500 |
+
|
501 |
+
.nav a {
|
502 |
+
font-size: 0.9rem;
|
503 |
+
}
|
504 |
+
|
505 |
+
.tabs {
|
506 |
+
flex-direction: column;
|
507 |
+
width: 100%;
|
508 |
+
}
|
509 |
+
|
510 |
+
.tab-btn {
|
511 |
+
width: 100%;
|
512 |
+
border-radius: var(--border-radius-md) !important;
|
513 |
+
margin-bottom: var(--spacing-sm);
|
514 |
+
}
|
515 |
+
|
516 |
+
.feature-card {
|
517 |
+
padding: var(--spacing-md);
|
518 |
+
}
|
519 |
+
}
|
frontend/index.html
ADDED
@@ -0,0 +1,169 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!DOCTYPE html>
|
2 |
+
<html lang="en">
|
3 |
+
<head>
|
4 |
+
<meta charset="UTF-8">
|
5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6 |
+
<title>AI Document & Image Analysis</title>
|
7 |
+
<link rel="stylesheet" href="css/styles.css">
|
8 |
+
<link rel="stylesheet" href="css/animations.css">
|
9 |
+
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap">
|
10 |
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
11 |
+
</head>
|
12 |
+
<body>
|
13 |
+
<header class="header">
|
14 |
+
<div class="container">
|
15 |
+
<div class="logo">
|
16 |
+
<i class="fas fa-brain"></i>
|
17 |
+
<h1>AI Document Analyzer</h1>
|
18 |
+
</div>
|
19 |
+
<nav class="nav">
|
20 |
+
<ul>
|
21 |
+
<li><a href="#" class="active">Home</a></li>
|
22 |
+
<li><a href="#features">Features</a></li>
|
23 |
+
<li><a href="#about">About</a></li>
|
24 |
+
</ul>
|
25 |
+
</nav>
|
26 |
+
</div>
|
27 |
+
</header>
|
28 |
+
|
29 |
+
<main>
|
30 |
+
<section class="hero">
|
31 |
+
<div class="container">
|
32 |
+
<div class="hero-content">
|
33 |
+
<h1 class="hero-title">Powerful AI Document & Image Analysis</h1>
|
34 |
+
<p class="hero-subtitle">Upload documents and images for instant AI-powered analysis, summarization, and interpretation.</p>
|
35 |
+
</div>
|
36 |
+
</div>
|
37 |
+
</section>
|
38 |
+
|
39 |
+
<section class="upload-section">
|
40 |
+
<div class="container">
|
41 |
+
<div class="tabs">
|
42 |
+
<button class="tab-btn active" data-tab="document">Document Analysis</button>
|
43 |
+
<button class="tab-btn" data-tab="image">Image Analysis</button>
|
44 |
+
</div>
|
45 |
+
|
46 |
+
<div class="tab-content active" id="document-tab">
|
47 |
+
<div class="upload-container" id="document-upload">
|
48 |
+
<div class="upload-area" id="document-drop-area">
|
49 |
+
<i class="fas fa-file-alt"></i>
|
50 |
+
<h3>Upload Document</h3>
|
51 |
+
<p>Drag & drop your document here or click to browse</p>
|
52 |
+
<p class="file-types">Supported formats: PDF, DOCX, PPTX, Excel</p>
|
53 |
+
<input type="file" id="document-file-input" accept=".pdf,.docx,.pptx,.xlsx,.xls" hidden>
|
54 |
+
</div>
|
55 |
+
|
56 |
+
<div class="analysis-options">
|
57 |
+
<h3>Analysis Options</h3>
|
58 |
+
<div class="radio-group">
|
59 |
+
<div class="radio-option">
|
60 |
+
<input type="radio" id="doc-summarize" name="document-analysis" value="summarize" checked>
|
61 |
+
<label for="doc-summarize">Summarize Document</label>
|
62 |
+
</div>
|
63 |
+
</div>
|
64 |
+
<button class="analyze-btn" id="analyze-document-btn" disabled>Analyze Document</button>
|
65 |
+
</div>
|
66 |
+
</div>
|
67 |
+
</div>
|
68 |
+
|
69 |
+
<div class="tab-content" id="image-tab">
|
70 |
+
<div class="upload-container" id="image-upload">
|
71 |
+
<div class="upload-area" id="image-drop-area">
|
72 |
+
<i class="fas fa-image"></i>
|
73 |
+
<h3>Upload Image</h3>
|
74 |
+
<p>Drag & drop your image here or click to browse</p>
|
75 |
+
<p class="file-types">Supported formats: JPG, JPEG, PNG</p>
|
76 |
+
<input type="file" id="image-file-input" accept=".jpg,.jpeg,.png" hidden>
|
77 |
+
</div>
|
78 |
+
|
79 |
+
<div class="analysis-options">
|
80 |
+
<h3>Analysis Options</h3>
|
81 |
+
<div class="radio-group">
|
82 |
+
<div class="radio-option">
|
83 |
+
<input type="radio" id="img-caption" name="image-analysis" value="caption" checked>
|
84 |
+
<label for="img-caption">Generate Caption</label>
|
85 |
+
</div>
|
86 |
+
</div>
|
87 |
+
<button class="analyze-btn" id="analyze-image-btn" disabled>Analyze Image</button>
|
88 |
+
</div>
|
89 |
+
</div>
|
90 |
+
</div>
|
91 |
+
|
92 |
+
<div class="results-container" id="results-container" style="display: none;">
|
93 |
+
<div class="results-header">
|
94 |
+
<h2>Analysis Results</h2>
|
95 |
+
<div class="results-actions">
|
96 |
+
<button id="copy-results" class="action-btn"><i class="fas fa-copy"></i> Copy</button>
|
97 |
+
<button id="close-results" class="action-btn"><i class="fas fa-times"></i> Close</button>
|
98 |
+
</div>
|
99 |
+
</div>
|
100 |
+
<div class="results-content" id="results-content">
|
101 |
+
<!-- Results will be displayed here -->
|
102 |
+
</div>
|
103 |
+
</div>
|
104 |
+
</div>
|
105 |
+
</section>
|
106 |
+
|
107 |
+
<section class="features" id="features">
|
108 |
+
<div class="container">
|
109 |
+
<h2 class="section-title">Features</h2>
|
110 |
+
<div class="features-grid">
|
111 |
+
<div class="feature-card">
|
112 |
+
<div class="feature-icon">
|
113 |
+
<i class="fas fa-file-alt"></i>
|
114 |
+
</div>
|
115 |
+
<h3>Document Summarization</h3>
|
116 |
+
<p>Extract key information from documents and get concise summaries.</p>
|
117 |
+
</div>
|
118 |
+
<div class="feature-card">
|
119 |
+
<div class="feature-icon">
|
120 |
+
<i class="fas fa-image"></i>
|
121 |
+
</div>
|
122 |
+
<h3>Image Captioning</h3>
|
123 |
+
<p>Generate descriptive captions for images using AI vision models.</p>
|
124 |
+
</div>
|
125 |
+
<div class="feature-card">
|
126 |
+
<div class="feature-icon">
|
127 |
+
<i class="fas fa-bolt"></i>
|
128 |
+
</div>
|
129 |
+
<h3>Fast Processing</h3>
|
130 |
+
<p>Powered by state-of-the-art Hugging Face AI models for quick results.</p>
|
131 |
+
</div>
|
132 |
+
<div class="feature-card">
|
133 |
+
<div class="feature-icon">
|
134 |
+
<i class="fas fa-lock"></i>
|
135 |
+
</div>
|
136 |
+
<h3>Secure Analysis</h3>
|
137 |
+
<p>Your files are processed securely and not stored permanently.</p>
|
138 |
+
</div>
|
139 |
+
</div>
|
140 |
+
</div>
|
141 |
+
</section>
|
142 |
+
|
143 |
+
<section class="about" id="about">
|
144 |
+
<div class="container">
|
145 |
+
<h2 class="section-title">About</h2>
|
146 |
+
<div class="about-content">
|
147 |
+
<p>This AI Document Analyzer uses state-of-the-art models from Hugging Face to provide accurate document summarization and image captioning. Built with Python FastAPI and deployed on Hugging Face Spaces, this tool demonstrates the power of AI in document and image analysis.</p>
|
148 |
+
<p>The application leverages powerful language and vision models to extract meaning from your documents and images, providing valuable insights and saving you time.</p>
|
149 |
+
</div>
|
150 |
+
</div>
|
151 |
+
</section>
|
152 |
+
</main>
|
153 |
+
|
154 |
+
<footer class="footer">
|
155 |
+
<div class="container">
|
156 |
+
<p>© 2025 AI Document Analyzer. Built with <i class="fas fa-heart"></i> and Hugging Face AI.</p>
|
157 |
+
</div>
|
158 |
+
</footer>
|
159 |
+
|
160 |
+
<div class="loading-overlay" id="loading-overlay">
|
161 |
+
<div class="spinner"></div>
|
162 |
+
<p>Processing your file...</p>
|
163 |
+
</div>
|
164 |
+
|
165 |
+
<script src="js/main.js"></script>
|
166 |
+
<script src="js/upload.js"></script>
|
167 |
+
<script src="js/results.js"></script>
|
168 |
+
</body>
|
169 |
+
</html>
|
frontend/js/main.js
ADDED
@@ -0,0 +1,132 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Main JavaScript file for AI Document Analyzer
|
3 |
+
*/
|
4 |
+
|
5 |
+
document.addEventListener('DOMContentLoaded', () => {
|
6 |
+
// Initialize tabs
|
7 |
+
initTabs();
|
8 |
+
|
9 |
+
// Initialize animations
|
10 |
+
initAnimations();
|
11 |
+
});
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Initialize tab functionality
|
15 |
+
*/
|
16 |
+
function initTabs() {
|
17 |
+
const tabBtns = document.querySelectorAll('.tab-btn');
|
18 |
+
const tabContents = document.querySelectorAll('.tab-content');
|
19 |
+
|
20 |
+
tabBtns.forEach(btn => {
|
21 |
+
btn.addEventListener('click', () => {
|
22 |
+
// Remove active class from all buttons and contents
|
23 |
+
tabBtns.forEach(b => b.classList.remove('active'));
|
24 |
+
tabContents.forEach(c => c.classList.remove('active'));
|
25 |
+
|
26 |
+
// Add active class to clicked button and corresponding content
|
27 |
+
btn.classList.add('active');
|
28 |
+
const tabId = `${btn.dataset.tab}-tab`;
|
29 |
+
document.getElementById(tabId).classList.add('active');
|
30 |
+
});
|
31 |
+
});
|
32 |
+
}
|
33 |
+
|
34 |
+
/**
|
35 |
+
* Initialize animations
|
36 |
+
*/
|
37 |
+
function initAnimations() {
|
38 |
+
// Intersection Observer for scroll animations
|
39 |
+
const observer = new IntersectionObserver((entries) => {
|
40 |
+
entries.forEach(entry => {
|
41 |
+
if (entry.isIntersecting) {
|
42 |
+
entry.target.classList.add('appear');
|
43 |
+
}
|
44 |
+
});
|
45 |
+
}, {
|
46 |
+
threshold: 0.2
|
47 |
+
});
|
48 |
+
|
49 |
+
// Observe elements that should animate on scroll
|
50 |
+
const animatedElements = document.querySelectorAll('.section-title, .feature-card, .about-content p');
|
51 |
+
animatedElements.forEach(element => {
|
52 |
+
observer.observe(element);
|
53 |
+
});
|
54 |
+
}
|
55 |
+
|
56 |
+
/**
|
57 |
+
* Show loading overlay
|
58 |
+
*/
|
59 |
+
function showLoading() {
|
60 |
+
const loadingOverlay = document.getElementById('loading-overlay');
|
61 |
+
loadingOverlay.style.display = 'flex';
|
62 |
+
}
|
63 |
+
|
64 |
+
/**
|
65 |
+
* Hide loading overlay
|
66 |
+
*/
|
67 |
+
function hideLoading() {
|
68 |
+
const loadingOverlay = document.getElementById('loading-overlay');
|
69 |
+
loadingOverlay.style.display = 'none';
|
70 |
+
}
|
71 |
+
|
72 |
+
/**
|
73 |
+
* Display error message
|
74 |
+
* @param {string} message - The error message to display
|
75 |
+
*/
|
76 |
+
function showError(message) {
|
77 |
+
// Create error notification
|
78 |
+
const notification = document.createElement('div');
|
79 |
+
notification.className = 'error-notification fade-in';
|
80 |
+
notification.innerHTML = `
|
81 |
+
<div class="error-icon"><i class="fas fa-exclamation-circle"></i></div>
|
82 |
+
<div class="error-message">${message}</div>
|
83 |
+
`;
|
84 |
+
|
85 |
+
// Add to DOM
|
86 |
+
document.body.appendChild(notification);
|
87 |
+
|
88 |
+
// Remove after delay
|
89 |
+
setTimeout(() => {
|
90 |
+
notification.classList.add('fade-out');
|
91 |
+
setTimeout(() => {
|
92 |
+
document.body.removeChild(notification);
|
93 |
+
}, 500);
|
94 |
+
}, 4000);
|
95 |
+
}
|
96 |
+
|
97 |
+
/**
|
98 |
+
* Format file size in human-readable format
|
99 |
+
* @param {number} bytes - File size in bytes
|
100 |
+
* @returns {string} Formatted file size
|
101 |
+
*/
|
102 |
+
function formatFileSize(bytes) {
|
103 |
+
if (bytes === 0) return '0 Bytes';
|
104 |
+
|
105 |
+
const k = 1024;
|
106 |
+
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
|
107 |
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
108 |
+
|
109 |
+
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
110 |
+
}
|
111 |
+
|
112 |
+
/**
|
113 |
+
* Get file extension from filename
|
114 |
+
* @param {string} filename - The name of the file
|
115 |
+
* @returns {string} The file extension
|
116 |
+
*/
|
117 |
+
function getFileExtension(filename) {
|
118 |
+
return filename.slice((filename.lastIndexOf('.') - 1 >>> 0) + 2).toLowerCase();
|
119 |
+
}
|
120 |
+
|
121 |
+
/**
|
122 |
+
* Check if file type is allowed
|
123 |
+
* @param {string} fileType - The type of file
|
124 |
+
* @param {string} allowedTypes - Comma-separated list of allowed types
|
125 |
+
* @returns {boolean} Whether the file type is allowed
|
126 |
+
*/
|
127 |
+
function isFileTypeAllowed(filename, allowedTypes) {
|
128 |
+
const extension = getFileExtension(filename);
|
129 |
+
const allowedExtensions = allowedTypes.split(',').map(type => type.trim().replace('.', '').toLowerCase());
|
130 |
+
|
131 |
+
return allowedExtensions.includes(extension);
|
132 |
+
}
|
frontend/js/results.js
ADDED
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Results handling for AI Document Analyzer
|
3 |
+
*/
|
4 |
+
|
5 |
+
document.addEventListener('DOMContentLoaded', () => {
|
6 |
+
// Initialize results functionality
|
7 |
+
initResults();
|
8 |
+
});
|
9 |
+
|
10 |
+
/**
|
11 |
+
* Initialize results functionality
|
12 |
+
*/
|
13 |
+
function initResults() {
|
14 |
+
const resultsContainer = document.getElementById('results-container');
|
15 |
+
const resultsContent = document.getElementById('results-content');
|
16 |
+
const copyBtn = document.getElementById('copy-results');
|
17 |
+
const closeBtn = document.getElementById('close-results');
|
18 |
+
|
19 |
+
// Copy results
|
20 |
+
copyBtn.addEventListener('click', () => {
|
21 |
+
const text = resultsContent.textContent;
|
22 |
+
navigator.clipboard.writeText(text)
|
23 |
+
.then(() => {
|
24 |
+
// Show copy success animation
|
25 |
+
copyBtn.innerHTML = '<i class="fas fa-check"></i> Copied!';
|
26 |
+
setTimeout(() => {
|
27 |
+
copyBtn.innerHTML = '<i class="fas fa-copy"></i> Copy';
|
28 |
+
}, 2000);
|
29 |
+
})
|
30 |
+
.catch(err => {
|
31 |
+
showError('Failed to copy: ' + err);
|
32 |
+
});
|
33 |
+
});
|
34 |
+
|
35 |
+
// Close results
|
36 |
+
closeBtn.addEventListener('click', () => {
|
37 |
+
resultsContainer.style.display = 'none';
|
38 |
+
});
|
39 |
+
}
|
40 |
+
|
41 |
+
/**
|
42 |
+
* Display analysis results
|
43 |
+
* @param {Object} data - The analysis results data
|
44 |
+
*/
|
45 |
+
function displayResults(data) {
|
46 |
+
const resultsContainer = document.getElementById('results-container');
|
47 |
+
const resultsContent = document.getElementById('results-content');
|
48 |
+
|
49 |
+
// Format the results
|
50 |
+
let formattedResults = '';
|
51 |
+
|
52 |
+
// Add file info
|
53 |
+
formattedResults += `File: ${data.filename}\n`;
|
54 |
+
formattedResults += `Analysis Type: ${formatAnalysisType(data.analysis_type)}\n\n`;
|
55 |
+
|
56 |
+
// Add result
|
57 |
+
formattedResults += `${data.result}\n`;
|
58 |
+
|
59 |
+
// Set content
|
60 |
+
resultsContent.textContent = formattedResults;
|
61 |
+
|
62 |
+
// Show results container with animation
|
63 |
+
resultsContainer.style.display = 'block';
|
64 |
+
resultsContainer.classList.add('slide-up');
|
65 |
+
|
66 |
+
// Scroll to results
|
67 |
+
resultsContainer.scrollIntoView({ behavior: 'smooth' });
|
68 |
+
}
|
69 |
+
|
70 |
+
/**
|
71 |
+
* Format analysis type for display
|
72 |
+
* @param {string} type - The analysis type
|
73 |
+
* @returns {string} Formatted analysis type
|
74 |
+
*/
|
75 |
+
function formatAnalysisType(type) {
|
76 |
+
const typeMap = {
|
77 |
+
'summarize': 'Document Summarization',
|
78 |
+
'caption': 'Image Captioning'
|
79 |
+
};
|
80 |
+
|
81 |
+
return typeMap[type] || type;
|
82 |
+
}
|
frontend/js/upload.js
ADDED
@@ -0,0 +1,261 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Upload functionality for AI Document Analyzer
|
3 |
+
*/
|
4 |
+
|
5 |
+
document.addEventListener('DOMContentLoaded', () => {
|
6 |
+
// Initialize document upload
|
7 |
+
initDocumentUpload();
|
8 |
+
|
9 |
+
// Initialize image upload
|
10 |
+
initImageUpload();
|
11 |
+
});
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Initialize document upload functionality
|
15 |
+
*/
|
16 |
+
function initDocumentUpload() {
|
17 |
+
const dropArea = document.getElementById('document-drop-area');
|
18 |
+
const fileInput = document.getElementById('document-file-input');
|
19 |
+
const analyzeBtn = document.getElementById('analyze-document-btn');
|
20 |
+
|
21 |
+
let selectedFile = null;
|
22 |
+
|
23 |
+
// Handle drag and drop events
|
24 |
+
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
|
25 |
+
dropArea.addEventListener(eventName, (e) => {
|
26 |
+
e.preventDefault();
|
27 |
+
e.stopPropagation();
|
28 |
+
});
|
29 |
+
});
|
30 |
+
|
31 |
+
// Add dragover class
|
32 |
+
dropArea.addEventListener('dragenter', () => {
|
33 |
+
dropArea.classList.add('dragover');
|
34 |
+
});
|
35 |
+
|
36 |
+
dropArea.addEventListener('dragover', () => {
|
37 |
+
dropArea.classList.add('dragover');
|
38 |
+
});
|
39 |
+
|
40 |
+
// Remove dragover class
|
41 |
+
dropArea.addEventListener('dragleave', () => {
|
42 |
+
dropArea.classList.remove('dragover');
|
43 |
+
});
|
44 |
+
|
45 |
+
// Handle file drop
|
46 |
+
dropArea.addEventListener('drop', (e) => {
|
47 |
+
dropArea.classList.remove('dragover');
|
48 |
+
const file = e.dataTransfer.files[0];
|
49 |
+
handleDocumentFile(file);
|
50 |
+
});
|
51 |
+
|
52 |
+
// Handle click to browse
|
53 |
+
dropArea.addEventListener('click', () => {
|
54 |
+
fileInput.click();
|
55 |
+
});
|
56 |
+
|
57 |
+
// Handle file selection
|
58 |
+
fileInput.addEventListener('change', () => {
|
59 |
+
const file = fileInput.files[0];
|
60 |
+
handleDocumentFile(file);
|
61 |
+
});
|
62 |
+
|
63 |
+
// Handle analyze button click
|
64 |
+
analyzeBtn.addEventListener('click', () => {
|
65 |
+
if (selectedFile) {
|
66 |
+
const analysisType = document.querySelector('input[name="document-analysis"]:checked').value;
|
67 |
+
uploadDocumentForAnalysis(selectedFile, analysisType);
|
68 |
+
}
|
69 |
+
});
|
70 |
+
|
71 |
+
/**
|
72 |
+
* Handle document file selection
|
73 |
+
* @param {File} file - The selected file
|
74 |
+
*/
|
75 |
+
function handleDocumentFile(file) {
|
76 |
+
if (!file) return;
|
77 |
+
|
78 |
+
// Check if file type is allowed
|
79 |
+
const allowedTypes = '.pdf,.docx,.pptx,.xlsx,.xls';
|
80 |
+
if (!isFileTypeAllowed(file.name, allowedTypes)) {
|
81 |
+
showError('File type not supported. Please upload a PDF, DOCX, PPTX, or Excel file.');
|
82 |
+
return;
|
83 |
+
}
|
84 |
+
|
85 |
+
// Update UI to show selected file
|
86 |
+
dropArea.classList.add('file-selected');
|
87 |
+
dropArea.innerHTML = `
|
88 |
+
<i class="fas fa-file-alt"></i>
|
89 |
+
<h3>${file.name}</h3>
|
90 |
+
<p>${formatFileSize(file.size)}</p>
|
91 |
+
<p class="file-types">Click to change file</p>
|
92 |
+
`;
|
93 |
+
|
94 |
+
// Enable analyze button
|
95 |
+
analyzeBtn.disabled = false;
|
96 |
+
|
97 |
+
// Store selected file
|
98 |
+
selectedFile = file;
|
99 |
+
}
|
100 |
+
|
101 |
+
/**
|
102 |
+
* Upload document for analysis
|
103 |
+
* @param {File} file - The document file to analyze
|
104 |
+
* @param {string} analysisType - The type of analysis to perform
|
105 |
+
*/
|
106 |
+
function uploadDocumentForAnalysis(file, analysisType) {
|
107 |
+
showLoading();
|
108 |
+
|
109 |
+
const formData = new FormData();
|
110 |
+
formData.append('file', file);
|
111 |
+
formData.append('analysis_type', analysisType);
|
112 |
+
|
113 |
+
fetch('/api/analyze-document', {
|
114 |
+
method: 'POST',
|
115 |
+
body: formData
|
116 |
+
})
|
117 |
+
.then(response => {
|
118 |
+
if (!response.ok) {
|
119 |
+
return response.json().then(data => {
|
120 |
+
throw new Error(data.detail || 'Error analyzing document');
|
121 |
+
});
|
122 |
+
}
|
123 |
+
return response.json();
|
124 |
+
})
|
125 |
+
.then(data => {
|
126 |
+
hideLoading();
|
127 |
+
displayResults(data);
|
128 |
+
})
|
129 |
+
.catch(error => {
|
130 |
+
hideLoading();
|
131 |
+
showError(error.message);
|
132 |
+
});
|
133 |
+
}
|
134 |
+
}
|
135 |
+
|
136 |
+
/**
|
137 |
+
* Initialize image upload functionality
|
138 |
+
*/
|
139 |
+
function initImageUpload() {
|
140 |
+
const dropArea = document.getElementById('image-drop-area');
|
141 |
+
const fileInput = document.getElementById('image-file-input');
|
142 |
+
const analyzeBtn = document.getElementById('analyze-image-btn');
|
143 |
+
|
144 |
+
let selectedFile = null;
|
145 |
+
|
146 |
+
// Handle drag and drop events
|
147 |
+
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
|
148 |
+
dropArea.addEventListener(eventName, (e) => {
|
149 |
+
e.preventDefault();
|
150 |
+
e.stopPropagation();
|
151 |
+
});
|
152 |
+
});
|
153 |
+
|
154 |
+
// Add dragover class
|
155 |
+
dropArea.addEventListener('dragenter', () => {
|
156 |
+
dropArea.classList.add('dragover');
|
157 |
+
});
|
158 |
+
|
159 |
+
dropArea.addEventListener('dragover', () => {
|
160 |
+
dropArea.classList.add('dragover');
|
161 |
+
});
|
162 |
+
|
163 |
+
// Remove dragover class
|
164 |
+
dropArea.addEventListener('dragleave', () => {
|
165 |
+
dropArea.classList.remove('dragover');
|
166 |
+
});
|
167 |
+
|
168 |
+
// Handle file drop
|
169 |
+
dropArea.addEventListener('drop', (e) => {
|
170 |
+
dropArea.classList.remove('dragover');
|
171 |
+
const file = e.dataTransfer.files[0];
|
172 |
+
handleImageFile(file);
|
173 |
+
});
|
174 |
+
|
175 |
+
// Handle click to browse
|
176 |
+
dropArea.addEventListener('click', () => {
|
177 |
+
fileInput.click();
|
178 |
+
});
|
179 |
+
|
180 |
+
// Handle file selection
|
181 |
+
fileInput.addEventListener('change', () => {
|
182 |
+
const file = fileInput.files[0];
|
183 |
+
handleImageFile(file);
|
184 |
+
});
|
185 |
+
|
186 |
+
// Handle analyze button click
|
187 |
+
analyzeBtn.addEventListener('click', () => {
|
188 |
+
if (selectedFile) {
|
189 |
+
const analysisType = document.querySelector('input[name="image-analysis"]:checked').value;
|
190 |
+
uploadImageForAnalysis(selectedFile, analysisType);
|
191 |
+
}
|
192 |
+
});
|
193 |
+
|
194 |
+
/**
|
195 |
+
* Handle image file selection
|
196 |
+
* @param {File} file - The selected file
|
197 |
+
*/
|
198 |
+
function handleImageFile(file) {
|
199 |
+
if (!file) return;
|
200 |
+
|
201 |
+
// Check if file type is allowed
|
202 |
+
const allowedTypes = '.jpg,.jpeg,.png';
|
203 |
+
if (!isFileTypeAllowed(file.name, allowedTypes)) {
|
204 |
+
showError('File type not supported. Please upload a JPG, JPEG, or PNG file.');
|
205 |
+
return;
|
206 |
+
}
|
207 |
+
|
208 |
+
// Create a preview of the image
|
209 |
+
const reader = new FileReader();
|
210 |
+
reader.onload = function(e) {
|
211 |
+
dropArea.classList.add('file-selected');
|
212 |
+
dropArea.innerHTML = `
|
213 |
+
<img src="${e.target.result}" alt="Preview" style="max-width: 100%; max-height: 200px; margin-bottom: 16px;">
|
214 |
+
<h3>${file.name}</h3>
|
215 |
+
<p>${formatFileSize(file.size)}</p>
|
216 |
+
<p class="file-types">Click to change image</p>
|
217 |
+
`;
|
218 |
+
};
|
219 |
+
reader.readAsDataURL(file);
|
220 |
+
|
221 |
+
// Enable analyze button
|
222 |
+
analyzeBtn.disabled = false;
|
223 |
+
|
224 |
+
// Store selected file
|
225 |
+
selectedFile = file;
|
226 |
+
}
|
227 |
+
|
228 |
+
/**
|
229 |
+
* Upload image for analysis
|
230 |
+
* @param {File} file - The image file to analyze
|
231 |
+
* @param {string} analysisType - The type of analysis to perform
|
232 |
+
*/
|
233 |
+
function uploadImageForAnalysis(file, analysisType) {
|
234 |
+
showLoading();
|
235 |
+
|
236 |
+
const formData = new FormData();
|
237 |
+
formData.append('file', file);
|
238 |
+
formData.append('analysis_type', analysisType);
|
239 |
+
|
240 |
+
fetch('/api/analyze-image', {
|
241 |
+
method: 'POST',
|
242 |
+
body: formData
|
243 |
+
})
|
244 |
+
.then(response => {
|
245 |
+
if (!response.ok) {
|
246 |
+
return response.json().then(data => {
|
247 |
+
throw new Error(data.detail || 'Error analyzing image');
|
248 |
+
});
|
249 |
+
}
|
250 |
+
return response.json();
|
251 |
+
})
|
252 |
+
.then(data => {
|
253 |
+
hideLoading();
|
254 |
+
displayResults(data);
|
255 |
+
})
|
256 |
+
.catch(error => {
|
257 |
+
hideLoading();
|
258 |
+
showError(error.message);
|
259 |
+
});
|
260 |
+
}
|
261 |
+
}
|
index.html
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!doctype html>
|
2 |
+
<html lang="en">
|
3 |
+
<head>
|
4 |
+
<meta charset="UTF-8" />
|
5 |
+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
6 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
7 |
+
<title>AI Document Analysis Web Application</title>
|
8 |
+
</head>
|
9 |
+
<body>
|
10 |
+
<div id="app"></div>
|
11 |
+
<script type="module" src="/main.js"></script>
|
12 |
+
</body>
|
13 |
+
</html>
|
javascript.svg
ADDED
|
main.js
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import './style.css'
|
2 |
+
import javascriptLogo from './javascript.svg'
|
3 |
+
import viteLogo from '/vite.svg'
|
4 |
+
import { setupCounter } from './counter.js'
|
5 |
+
|
6 |
+
document.querySelector('#app').innerHTML = `
|
7 |
+
<div>
|
8 |
+
<a href="https://vitejs.dev" target="_blank">
|
9 |
+
<img src="${viteLogo}" class="logo" alt="Vite logo" />
|
10 |
+
</a>
|
11 |
+
<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript" target="_blank">
|
12 |
+
<img src="${javascriptLogo}" class="logo vanilla" alt="JavaScript logo" />
|
13 |
+
</a>
|
14 |
+
<h1>Hello Vite!</h1>
|
15 |
+
<div class="card">
|
16 |
+
<button id="counter" type="button"></button>
|
17 |
+
</div>
|
18 |
+
<p class="read-the-docs">
|
19 |
+
Click on the Vite logo to learn more
|
20 |
+
</p>
|
21 |
+
</div>
|
22 |
+
`
|
23 |
+
|
24 |
+
setupCounter(document.querySelector('#counter'))
|
package-lock.json
ADDED
@@ -0,0 +1,912 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"name": "vite-starter",
|
3 |
+
"version": "0.0.0",
|
4 |
+
"lockfileVersion": 3,
|
5 |
+
"requires": true,
|
6 |
+
"packages": {
|
7 |
+
"": {
|
8 |
+
"name": "vite-starter",
|
9 |
+
"version": "0.0.0",
|
10 |
+
"devDependencies": {
|
11 |
+
"vite": "^5.4.2"
|
12 |
+
}
|
13 |
+
},
|
14 |
+
"node_modules/@esbuild/aix-ppc64": {
|
15 |
+
"version": "0.21.5",
|
16 |
+
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
|
17 |
+
"integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==",
|
18 |
+
"cpu": [
|
19 |
+
"ppc64"
|
20 |
+
],
|
21 |
+
"dev": true,
|
22 |
+
"license": "MIT",
|
23 |
+
"optional": true,
|
24 |
+
"os": [
|
25 |
+
"aix"
|
26 |
+
],
|
27 |
+
"engines": {
|
28 |
+
"node": ">=12"
|
29 |
+
}
|
30 |
+
},
|
31 |
+
"node_modules/@esbuild/android-arm": {
|
32 |
+
"version": "0.21.5",
|
33 |
+
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz",
|
34 |
+
"integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==",
|
35 |
+
"cpu": [
|
36 |
+
"arm"
|
37 |
+
],
|
38 |
+
"dev": true,
|
39 |
+
"license": "MIT",
|
40 |
+
"optional": true,
|
41 |
+
"os": [
|
42 |
+
"android"
|
43 |
+
],
|
44 |
+
"engines": {
|
45 |
+
"node": ">=12"
|
46 |
+
}
|
47 |
+
},
|
48 |
+
"node_modules/@esbuild/android-arm64": {
|
49 |
+
"version": "0.21.5",
|
50 |
+
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz",
|
51 |
+
"integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==",
|
52 |
+
"cpu": [
|
53 |
+
"arm64"
|
54 |
+
],
|
55 |
+
"dev": true,
|
56 |
+
"license": "MIT",
|
57 |
+
"optional": true,
|
58 |
+
"os": [
|
59 |
+
"android"
|
60 |
+
],
|
61 |
+
"engines": {
|
62 |
+
"node": ">=12"
|
63 |
+
}
|
64 |
+
},
|
65 |
+
"node_modules/@esbuild/android-x64": {
|
66 |
+
"version": "0.21.5",
|
67 |
+
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz",
|
68 |
+
"integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==",
|
69 |
+
"cpu": [
|
70 |
+
"x64"
|
71 |
+
],
|
72 |
+
"dev": true,
|
73 |
+
"license": "MIT",
|
74 |
+
"optional": true,
|
75 |
+
"os": [
|
76 |
+
"android"
|
77 |
+
],
|
78 |
+
"engines": {
|
79 |
+
"node": ">=12"
|
80 |
+
}
|
81 |
+
},
|
82 |
+
"node_modules/@esbuild/darwin-arm64": {
|
83 |
+
"version": "0.21.5",
|
84 |
+
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz",
|
85 |
+
"integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==",
|
86 |
+
"cpu": [
|
87 |
+
"arm64"
|
88 |
+
],
|
89 |
+
"dev": true,
|
90 |
+
"license": "MIT",
|
91 |
+
"optional": true,
|
92 |
+
"os": [
|
93 |
+
"darwin"
|
94 |
+
],
|
95 |
+
"engines": {
|
96 |
+
"node": ">=12"
|
97 |
+
}
|
98 |
+
},
|
99 |
+
"node_modules/@esbuild/darwin-x64": {
|
100 |
+
"version": "0.21.5",
|
101 |
+
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz",
|
102 |
+
"integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==",
|
103 |
+
"cpu": [
|
104 |
+
"x64"
|
105 |
+
],
|
106 |
+
"dev": true,
|
107 |
+
"license": "MIT",
|
108 |
+
"optional": true,
|
109 |
+
"os": [
|
110 |
+
"darwin"
|
111 |
+
],
|
112 |
+
"engines": {
|
113 |
+
"node": ">=12"
|
114 |
+
}
|
115 |
+
},
|
116 |
+
"node_modules/@esbuild/freebsd-arm64": {
|
117 |
+
"version": "0.21.5",
|
118 |
+
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz",
|
119 |
+
"integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==",
|
120 |
+
"cpu": [
|
121 |
+
"arm64"
|
122 |
+
],
|
123 |
+
"dev": true,
|
124 |
+
"license": "MIT",
|
125 |
+
"optional": true,
|
126 |
+
"os": [
|
127 |
+
"freebsd"
|
128 |
+
],
|
129 |
+
"engines": {
|
130 |
+
"node": ">=12"
|
131 |
+
}
|
132 |
+
},
|
133 |
+
"node_modules/@esbuild/freebsd-x64": {
|
134 |
+
"version": "0.21.5",
|
135 |
+
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz",
|
136 |
+
"integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==",
|
137 |
+
"cpu": [
|
138 |
+
"x64"
|
139 |
+
],
|
140 |
+
"dev": true,
|
141 |
+
"license": "MIT",
|
142 |
+
"optional": true,
|
143 |
+
"os": [
|
144 |
+
"freebsd"
|
145 |
+
],
|
146 |
+
"engines": {
|
147 |
+
"node": ">=12"
|
148 |
+
}
|
149 |
+
},
|
150 |
+
"node_modules/@esbuild/linux-arm": {
|
151 |
+
"version": "0.21.5",
|
152 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz",
|
153 |
+
"integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==",
|
154 |
+
"cpu": [
|
155 |
+
"arm"
|
156 |
+
],
|
157 |
+
"dev": true,
|
158 |
+
"license": "MIT",
|
159 |
+
"optional": true,
|
160 |
+
"os": [
|
161 |
+
"linux"
|
162 |
+
],
|
163 |
+
"engines": {
|
164 |
+
"node": ">=12"
|
165 |
+
}
|
166 |
+
},
|
167 |
+
"node_modules/@esbuild/linux-arm64": {
|
168 |
+
"version": "0.21.5",
|
169 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz",
|
170 |
+
"integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==",
|
171 |
+
"cpu": [
|
172 |
+
"arm64"
|
173 |
+
],
|
174 |
+
"dev": true,
|
175 |
+
"license": "MIT",
|
176 |
+
"optional": true,
|
177 |
+
"os": [
|
178 |
+
"linux"
|
179 |
+
],
|
180 |
+
"engines": {
|
181 |
+
"node": ">=12"
|
182 |
+
}
|
183 |
+
},
|
184 |
+
"node_modules/@esbuild/linux-ia32": {
|
185 |
+
"version": "0.21.5",
|
186 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz",
|
187 |
+
"integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==",
|
188 |
+
"cpu": [
|
189 |
+
"ia32"
|
190 |
+
],
|
191 |
+
"dev": true,
|
192 |
+
"license": "MIT",
|
193 |
+
"optional": true,
|
194 |
+
"os": [
|
195 |
+
"linux"
|
196 |
+
],
|
197 |
+
"engines": {
|
198 |
+
"node": ">=12"
|
199 |
+
}
|
200 |
+
},
|
201 |
+
"node_modules/@esbuild/linux-loong64": {
|
202 |
+
"version": "0.21.5",
|
203 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz",
|
204 |
+
"integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==",
|
205 |
+
"cpu": [
|
206 |
+
"loong64"
|
207 |
+
],
|
208 |
+
"dev": true,
|
209 |
+
"license": "MIT",
|
210 |
+
"optional": true,
|
211 |
+
"os": [
|
212 |
+
"linux"
|
213 |
+
],
|
214 |
+
"engines": {
|
215 |
+
"node": ">=12"
|
216 |
+
}
|
217 |
+
},
|
218 |
+
"node_modules/@esbuild/linux-mips64el": {
|
219 |
+
"version": "0.21.5",
|
220 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz",
|
221 |
+
"integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==",
|
222 |
+
"cpu": [
|
223 |
+
"mips64el"
|
224 |
+
],
|
225 |
+
"dev": true,
|
226 |
+
"license": "MIT",
|
227 |
+
"optional": true,
|
228 |
+
"os": [
|
229 |
+
"linux"
|
230 |
+
],
|
231 |
+
"engines": {
|
232 |
+
"node": ">=12"
|
233 |
+
}
|
234 |
+
},
|
235 |
+
"node_modules/@esbuild/linux-ppc64": {
|
236 |
+
"version": "0.21.5",
|
237 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz",
|
238 |
+
"integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==",
|
239 |
+
"cpu": [
|
240 |
+
"ppc64"
|
241 |
+
],
|
242 |
+
"dev": true,
|
243 |
+
"license": "MIT",
|
244 |
+
"optional": true,
|
245 |
+
"os": [
|
246 |
+
"linux"
|
247 |
+
],
|
248 |
+
"engines": {
|
249 |
+
"node": ">=12"
|
250 |
+
}
|
251 |
+
},
|
252 |
+
"node_modules/@esbuild/linux-riscv64": {
|
253 |
+
"version": "0.21.5",
|
254 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz",
|
255 |
+
"integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==",
|
256 |
+
"cpu": [
|
257 |
+
"riscv64"
|
258 |
+
],
|
259 |
+
"dev": true,
|
260 |
+
"license": "MIT",
|
261 |
+
"optional": true,
|
262 |
+
"os": [
|
263 |
+
"linux"
|
264 |
+
],
|
265 |
+
"engines": {
|
266 |
+
"node": ">=12"
|
267 |
+
}
|
268 |
+
},
|
269 |
+
"node_modules/@esbuild/linux-s390x": {
|
270 |
+
"version": "0.21.5",
|
271 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz",
|
272 |
+
"integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==",
|
273 |
+
"cpu": [
|
274 |
+
"s390x"
|
275 |
+
],
|
276 |
+
"dev": true,
|
277 |
+
"license": "MIT",
|
278 |
+
"optional": true,
|
279 |
+
"os": [
|
280 |
+
"linux"
|
281 |
+
],
|
282 |
+
"engines": {
|
283 |
+
"node": ">=12"
|
284 |
+
}
|
285 |
+
},
|
286 |
+
"node_modules/@esbuild/linux-x64": {
|
287 |
+
"version": "0.21.5",
|
288 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz",
|
289 |
+
"integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==",
|
290 |
+
"cpu": [
|
291 |
+
"x64"
|
292 |
+
],
|
293 |
+
"dev": true,
|
294 |
+
"license": "MIT",
|
295 |
+
"optional": true,
|
296 |
+
"os": [
|
297 |
+
"linux"
|
298 |
+
],
|
299 |
+
"engines": {
|
300 |
+
"node": ">=12"
|
301 |
+
}
|
302 |
+
},
|
303 |
+
"node_modules/@esbuild/netbsd-x64": {
|
304 |
+
"version": "0.21.5",
|
305 |
+
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
|
306 |
+
"integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==",
|
307 |
+
"cpu": [
|
308 |
+
"x64"
|
309 |
+
],
|
310 |
+
"dev": true,
|
311 |
+
"license": "MIT",
|
312 |
+
"optional": true,
|
313 |
+
"os": [
|
314 |
+
"netbsd"
|
315 |
+
],
|
316 |
+
"engines": {
|
317 |
+
"node": ">=12"
|
318 |
+
}
|
319 |
+
},
|
320 |
+
"node_modules/@esbuild/openbsd-x64": {
|
321 |
+
"version": "0.21.5",
|
322 |
+
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
|
323 |
+
"integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==",
|
324 |
+
"cpu": [
|
325 |
+
"x64"
|
326 |
+
],
|
327 |
+
"dev": true,
|
328 |
+
"license": "MIT",
|
329 |
+
"optional": true,
|
330 |
+
"os": [
|
331 |
+
"openbsd"
|
332 |
+
],
|
333 |
+
"engines": {
|
334 |
+
"node": ">=12"
|
335 |
+
}
|
336 |
+
},
|
337 |
+
"node_modules/@esbuild/sunos-x64": {
|
338 |
+
"version": "0.21.5",
|
339 |
+
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
|
340 |
+
"integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
|
341 |
+
"cpu": [
|
342 |
+
"x64"
|
343 |
+
],
|
344 |
+
"dev": true,
|
345 |
+
"license": "MIT",
|
346 |
+
"optional": true,
|
347 |
+
"os": [
|
348 |
+
"sunos"
|
349 |
+
],
|
350 |
+
"engines": {
|
351 |
+
"node": ">=12"
|
352 |
+
}
|
353 |
+
},
|
354 |
+
"node_modules/@esbuild/win32-arm64": {
|
355 |
+
"version": "0.21.5",
|
356 |
+
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
|
357 |
+
"integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
|
358 |
+
"cpu": [
|
359 |
+
"arm64"
|
360 |
+
],
|
361 |
+
"dev": true,
|
362 |
+
"license": "MIT",
|
363 |
+
"optional": true,
|
364 |
+
"os": [
|
365 |
+
"win32"
|
366 |
+
],
|
367 |
+
"engines": {
|
368 |
+
"node": ">=12"
|
369 |
+
}
|
370 |
+
},
|
371 |
+
"node_modules/@esbuild/win32-ia32": {
|
372 |
+
"version": "0.21.5",
|
373 |
+
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
|
374 |
+
"integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
|
375 |
+
"cpu": [
|
376 |
+
"ia32"
|
377 |
+
],
|
378 |
+
"dev": true,
|
379 |
+
"license": "MIT",
|
380 |
+
"optional": true,
|
381 |
+
"os": [
|
382 |
+
"win32"
|
383 |
+
],
|
384 |
+
"engines": {
|
385 |
+
"node": ">=12"
|
386 |
+
}
|
387 |
+
},
|
388 |
+
"node_modules/@esbuild/win32-x64": {
|
389 |
+
"version": "0.21.5",
|
390 |
+
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
|
391 |
+
"integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
|
392 |
+
"cpu": [
|
393 |
+
"x64"
|
394 |
+
],
|
395 |
+
"dev": true,
|
396 |
+
"license": "MIT",
|
397 |
+
"optional": true,
|
398 |
+
"os": [
|
399 |
+
"win32"
|
400 |
+
],
|
401 |
+
"engines": {
|
402 |
+
"node": ">=12"
|
403 |
+
}
|
404 |
+
},
|
405 |
+
"node_modules/@rollup/rollup-android-arm-eabi": {
|
406 |
+
"version": "4.40.0",
|
407 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.40.0.tgz",
|
408 |
+
"integrity": "sha512-+Fbls/diZ0RDerhE8kyC6hjADCXA1K4yVNlH0EYfd2XjyH0UGgzaQ8MlT0pCXAThfxv3QUAczHaL+qSv1E4/Cg==",
|
409 |
+
"cpu": [
|
410 |
+
"arm"
|
411 |
+
],
|
412 |
+
"dev": true,
|
413 |
+
"license": "MIT",
|
414 |
+
"optional": true,
|
415 |
+
"os": [
|
416 |
+
"android"
|
417 |
+
]
|
418 |
+
},
|
419 |
+
"node_modules/@rollup/rollup-android-arm64": {
|
420 |
+
"version": "4.40.0",
|
421 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.40.0.tgz",
|
422 |
+
"integrity": "sha512-PPA6aEEsTPRz+/4xxAmaoWDqh67N7wFbgFUJGMnanCFs0TV99M0M8QhhaSCks+n6EbQoFvLQgYOGXxlMGQe/6w==",
|
423 |
+
"cpu": [
|
424 |
+
"arm64"
|
425 |
+
],
|
426 |
+
"dev": true,
|
427 |
+
"license": "MIT",
|
428 |
+
"optional": true,
|
429 |
+
"os": [
|
430 |
+
"android"
|
431 |
+
]
|
432 |
+
},
|
433 |
+
"node_modules/@rollup/rollup-darwin-arm64": {
|
434 |
+
"version": "4.40.0",
|
435 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.40.0.tgz",
|
436 |
+
"integrity": "sha512-GwYOcOakYHdfnjjKwqpTGgn5a6cUX7+Ra2HeNj/GdXvO2VJOOXCiYYlRFU4CubFM67EhbmzLOmACKEfvp3J1kQ==",
|
437 |
+
"cpu": [
|
438 |
+
"arm64"
|
439 |
+
],
|
440 |
+
"dev": true,
|
441 |
+
"license": "MIT",
|
442 |
+
"optional": true,
|
443 |
+
"os": [
|
444 |
+
"darwin"
|
445 |
+
]
|
446 |
+
},
|
447 |
+
"node_modules/@rollup/rollup-darwin-x64": {
|
448 |
+
"version": "4.40.0",
|
449 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.40.0.tgz",
|
450 |
+
"integrity": "sha512-CoLEGJ+2eheqD9KBSxmma6ld01czS52Iw0e2qMZNpPDlf7Z9mj8xmMemxEucinev4LgHalDPczMyxzbq+Q+EtA==",
|
451 |
+
"cpu": [
|
452 |
+
"x64"
|
453 |
+
],
|
454 |
+
"dev": true,
|
455 |
+
"license": "MIT",
|
456 |
+
"optional": true,
|
457 |
+
"os": [
|
458 |
+
"darwin"
|
459 |
+
]
|
460 |
+
},
|
461 |
+
"node_modules/@rollup/rollup-freebsd-arm64": {
|
462 |
+
"version": "4.40.0",
|
463 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.40.0.tgz",
|
464 |
+
"integrity": "sha512-r7yGiS4HN/kibvESzmrOB/PxKMhPTlz+FcGvoUIKYoTyGd5toHp48g1uZy1o1xQvybwwpqpe010JrcGG2s5nkg==",
|
465 |
+
"cpu": [
|
466 |
+
"arm64"
|
467 |
+
],
|
468 |
+
"dev": true,
|
469 |
+
"license": "MIT",
|
470 |
+
"optional": true,
|
471 |
+
"os": [
|
472 |
+
"freebsd"
|
473 |
+
]
|
474 |
+
},
|
475 |
+
"node_modules/@rollup/rollup-freebsd-x64": {
|
476 |
+
"version": "4.40.0",
|
477 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.40.0.tgz",
|
478 |
+
"integrity": "sha512-mVDxzlf0oLzV3oZOr0SMJ0lSDd3xC4CmnWJ8Val8isp9jRGl5Dq//LLDSPFrasS7pSm6m5xAcKaw3sHXhBjoRw==",
|
479 |
+
"cpu": [
|
480 |
+
"x64"
|
481 |
+
],
|
482 |
+
"dev": true,
|
483 |
+
"license": "MIT",
|
484 |
+
"optional": true,
|
485 |
+
"os": [
|
486 |
+
"freebsd"
|
487 |
+
]
|
488 |
+
},
|
489 |
+
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
490 |
+
"version": "4.40.0",
|
491 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.40.0.tgz",
|
492 |
+
"integrity": "sha512-y/qUMOpJxBMy8xCXD++jeu8t7kzjlOCkoxxajL58G62PJGBZVl/Gwpm7JK9+YvlB701rcQTzjUZ1JgUoPTnoQA==",
|
493 |
+
"cpu": [
|
494 |
+
"arm"
|
495 |
+
],
|
496 |
+
"dev": true,
|
497 |
+
"license": "MIT",
|
498 |
+
"optional": true,
|
499 |
+
"os": [
|
500 |
+
"linux"
|
501 |
+
]
|
502 |
+
},
|
503 |
+
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
504 |
+
"version": "4.40.0",
|
505 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.40.0.tgz",
|
506 |
+
"integrity": "sha512-GoCsPibtVdJFPv/BOIvBKO/XmwZLwaNWdyD8TKlXuqp0veo2sHE+A/vpMQ5iSArRUz/uaoj4h5S6Pn0+PdhRjg==",
|
507 |
+
"cpu": [
|
508 |
+
"arm"
|
509 |
+
],
|
510 |
+
"dev": true,
|
511 |
+
"license": "MIT",
|
512 |
+
"optional": true,
|
513 |
+
"os": [
|
514 |
+
"linux"
|
515 |
+
]
|
516 |
+
},
|
517 |
+
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
518 |
+
"version": "4.40.0",
|
519 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.40.0.tgz",
|
520 |
+
"integrity": "sha512-L5ZLphTjjAD9leJzSLI7rr8fNqJMlGDKlazW2tX4IUF9P7R5TMQPElpH82Q7eNIDQnQlAyiNVfRPfP2vM5Avvg==",
|
521 |
+
"cpu": [
|
522 |
+
"arm64"
|
523 |
+
],
|
524 |
+
"dev": true,
|
525 |
+
"license": "MIT",
|
526 |
+
"optional": true,
|
527 |
+
"os": [
|
528 |
+
"linux"
|
529 |
+
]
|
530 |
+
},
|
531 |
+
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
532 |
+
"version": "4.40.0",
|
533 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.40.0.tgz",
|
534 |
+
"integrity": "sha512-ATZvCRGCDtv1Y4gpDIXsS+wfFeFuLwVxyUBSLawjgXK2tRE6fnsQEkE4csQQYWlBlsFztRzCnBvWVfcae/1qxQ==",
|
535 |
+
"cpu": [
|
536 |
+
"arm64"
|
537 |
+
],
|
538 |
+
"dev": true,
|
539 |
+
"license": "MIT",
|
540 |
+
"optional": true,
|
541 |
+
"os": [
|
542 |
+
"linux"
|
543 |
+
]
|
544 |
+
},
|
545 |
+
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
|
546 |
+
"version": "4.40.0",
|
547 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.40.0.tgz",
|
548 |
+
"integrity": "sha512-wG9e2XtIhd++QugU5MD9i7OnpaVb08ji3P1y/hNbxrQ3sYEelKJOq1UJ5dXczeo6Hj2rfDEL5GdtkMSVLa/AOg==",
|
549 |
+
"cpu": [
|
550 |
+
"loong64"
|
551 |
+
],
|
552 |
+
"dev": true,
|
553 |
+
"license": "MIT",
|
554 |
+
"optional": true,
|
555 |
+
"os": [
|
556 |
+
"linux"
|
557 |
+
]
|
558 |
+
},
|
559 |
+
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
|
560 |
+
"version": "4.40.0",
|
561 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.40.0.tgz",
|
562 |
+
"integrity": "sha512-vgXfWmj0f3jAUvC7TZSU/m/cOE558ILWDzS7jBhiCAFpY2WEBn5jqgbqvmzlMjtp8KlLcBlXVD2mkTSEQE6Ixw==",
|
563 |
+
"cpu": [
|
564 |
+
"ppc64"
|
565 |
+
],
|
566 |
+
"dev": true,
|
567 |
+
"license": "MIT",
|
568 |
+
"optional": true,
|
569 |
+
"os": [
|
570 |
+
"linux"
|
571 |
+
]
|
572 |
+
},
|
573 |
+
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
574 |
+
"version": "4.40.0",
|
575 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.40.0.tgz",
|
576 |
+
"integrity": "sha512-uJkYTugqtPZBS3Z136arevt/FsKTF/J9dEMTX/cwR7lsAW4bShzI2R0pJVw+hcBTWF4dxVckYh72Hk3/hWNKvA==",
|
577 |
+
"cpu": [
|
578 |
+
"riscv64"
|
579 |
+
],
|
580 |
+
"dev": true,
|
581 |
+
"license": "MIT",
|
582 |
+
"optional": true,
|
583 |
+
"os": [
|
584 |
+
"linux"
|
585 |
+
]
|
586 |
+
},
|
587 |
+
"node_modules/@rollup/rollup-linux-riscv64-musl": {
|
588 |
+
"version": "4.40.0",
|
589 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.40.0.tgz",
|
590 |
+
"integrity": "sha512-rKmSj6EXQRnhSkE22+WvrqOqRtk733x3p5sWpZilhmjnkHkpeCgWsFFo0dGnUGeA+OZjRl3+VYq+HyCOEuwcxQ==",
|
591 |
+
"cpu": [
|
592 |
+
"riscv64"
|
593 |
+
],
|
594 |
+
"dev": true,
|
595 |
+
"license": "MIT",
|
596 |
+
"optional": true,
|
597 |
+
"os": [
|
598 |
+
"linux"
|
599 |
+
]
|
600 |
+
},
|
601 |
+
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
602 |
+
"version": "4.40.0",
|
603 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.40.0.tgz",
|
604 |
+
"integrity": "sha512-SpnYlAfKPOoVsQqmTFJ0usx0z84bzGOS9anAC0AZ3rdSo3snecihbhFTlJZ8XMwzqAcodjFU4+/SM311dqE5Sw==",
|
605 |
+
"cpu": [
|
606 |
+
"s390x"
|
607 |
+
],
|
608 |
+
"dev": true,
|
609 |
+
"license": "MIT",
|
610 |
+
"optional": true,
|
611 |
+
"os": [
|
612 |
+
"linux"
|
613 |
+
]
|
614 |
+
},
|
615 |
+
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
616 |
+
"version": "4.40.0",
|
617 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.0.tgz",
|
618 |
+
"integrity": "sha512-RcDGMtqF9EFN8i2RYN2W+64CdHruJ5rPqrlYw+cgM3uOVPSsnAQps7cpjXe9be/yDp8UC7VLoCoKC8J3Kn2FkQ==",
|
619 |
+
"cpu": [
|
620 |
+
"x64"
|
621 |
+
],
|
622 |
+
"dev": true,
|
623 |
+
"license": "MIT",
|
624 |
+
"optional": true,
|
625 |
+
"os": [
|
626 |
+
"linux"
|
627 |
+
]
|
628 |
+
},
|
629 |
+
"node_modules/@rollup/rollup-linux-x64-musl": {
|
630 |
+
"version": "4.40.0",
|
631 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.40.0.tgz",
|
632 |
+
"integrity": "sha512-HZvjpiUmSNx5zFgwtQAV1GaGazT2RWvqeDi0hV+AtC8unqqDSsaFjPxfsO6qPtKRRg25SisACWnJ37Yio8ttaw==",
|
633 |
+
"cpu": [
|
634 |
+
"x64"
|
635 |
+
],
|
636 |
+
"dev": true,
|
637 |
+
"license": "MIT",
|
638 |
+
"optional": true,
|
639 |
+
"os": [
|
640 |
+
"linux"
|
641 |
+
]
|
642 |
+
},
|
643 |
+
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
644 |
+
"version": "4.40.0",
|
645 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.40.0.tgz",
|
646 |
+
"integrity": "sha512-UtZQQI5k/b8d7d3i9AZmA/t+Q4tk3hOC0tMOMSq2GlMYOfxbesxG4mJSeDp0EHs30N9bsfwUvs3zF4v/RzOeTQ==",
|
647 |
+
"cpu": [
|
648 |
+
"arm64"
|
649 |
+
],
|
650 |
+
"dev": true,
|
651 |
+
"license": "MIT",
|
652 |
+
"optional": true,
|
653 |
+
"os": [
|
654 |
+
"win32"
|
655 |
+
]
|
656 |
+
},
|
657 |
+
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
658 |
+
"version": "4.40.0",
|
659 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.40.0.tgz",
|
660 |
+
"integrity": "sha512-+m03kvI2f5syIqHXCZLPVYplP8pQch9JHyXKZ3AGMKlg8dCyr2PKHjwRLiW53LTrN/Nc3EqHOKxUxzoSPdKddA==",
|
661 |
+
"cpu": [
|
662 |
+
"ia32"
|
663 |
+
],
|
664 |
+
"dev": true,
|
665 |
+
"license": "MIT",
|
666 |
+
"optional": true,
|
667 |
+
"os": [
|
668 |
+
"win32"
|
669 |
+
]
|
670 |
+
},
|
671 |
+
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
672 |
+
"version": "4.40.0",
|
673 |
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.40.0.tgz",
|
674 |
+
"integrity": "sha512-lpPE1cLfP5oPzVjKMx10pgBmKELQnFJXHgvtHCtuJWOv8MxqdEIMNtgHgBFf7Ea2/7EuVwa9fodWUfXAlXZLZQ==",
|
675 |
+
"cpu": [
|
676 |
+
"x64"
|
677 |
+
],
|
678 |
+
"dev": true,
|
679 |
+
"license": "MIT",
|
680 |
+
"optional": true,
|
681 |
+
"os": [
|
682 |
+
"win32"
|
683 |
+
]
|
684 |
+
},
|
685 |
+
"node_modules/@types/estree": {
|
686 |
+
"version": "1.0.7",
|
687 |
+
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz",
|
688 |
+
"integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==",
|
689 |
+
"dev": true,
|
690 |
+
"license": "MIT"
|
691 |
+
},
|
692 |
+
"node_modules/esbuild": {
|
693 |
+
"version": "0.21.5",
|
694 |
+
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
|
695 |
+
"integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
|
696 |
+
"dev": true,
|
697 |
+
"hasInstallScript": true,
|
698 |
+
"license": "MIT",
|
699 |
+
"bin": {
|
700 |
+
"esbuild": "bin/esbuild"
|
701 |
+
},
|
702 |
+
"engines": {
|
703 |
+
"node": ">=12"
|
704 |
+
},
|
705 |
+
"optionalDependencies": {
|
706 |
+
"@esbuild/aix-ppc64": "0.21.5",
|
707 |
+
"@esbuild/android-arm": "0.21.5",
|
708 |
+
"@esbuild/android-arm64": "0.21.5",
|
709 |
+
"@esbuild/android-x64": "0.21.5",
|
710 |
+
"@esbuild/darwin-arm64": "0.21.5",
|
711 |
+
"@esbuild/darwin-x64": "0.21.5",
|
712 |
+
"@esbuild/freebsd-arm64": "0.21.5",
|
713 |
+
"@esbuild/freebsd-x64": "0.21.5",
|
714 |
+
"@esbuild/linux-arm": "0.21.5",
|
715 |
+
"@esbuild/linux-arm64": "0.21.5",
|
716 |
+
"@esbuild/linux-ia32": "0.21.5",
|
717 |
+
"@esbuild/linux-loong64": "0.21.5",
|
718 |
+
"@esbuild/linux-mips64el": "0.21.5",
|
719 |
+
"@esbuild/linux-ppc64": "0.21.5",
|
720 |
+
"@esbuild/linux-riscv64": "0.21.5",
|
721 |
+
"@esbuild/linux-s390x": "0.21.5",
|
722 |
+
"@esbuild/linux-x64": "0.21.5",
|
723 |
+
"@esbuild/netbsd-x64": "0.21.5",
|
724 |
+
"@esbuild/openbsd-x64": "0.21.5",
|
725 |
+
"@esbuild/sunos-x64": "0.21.5",
|
726 |
+
"@esbuild/win32-arm64": "0.21.5",
|
727 |
+
"@esbuild/win32-ia32": "0.21.5",
|
728 |
+
"@esbuild/win32-x64": "0.21.5"
|
729 |
+
}
|
730 |
+
},
|
731 |
+
"node_modules/fsevents": {
|
732 |
+
"version": "2.3.3",
|
733 |
+
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
734 |
+
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
735 |
+
"dev": true,
|
736 |
+
"hasInstallScript": true,
|
737 |
+
"license": "MIT",
|
738 |
+
"optional": true,
|
739 |
+
"os": [
|
740 |
+
"darwin"
|
741 |
+
],
|
742 |
+
"engines": {
|
743 |
+
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
744 |
+
}
|
745 |
+
},
|
746 |
+
"node_modules/nanoid": {
|
747 |
+
"version": "3.3.11",
|
748 |
+
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
|
749 |
+
"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
|
750 |
+
"dev": true,
|
751 |
+
"funding": [
|
752 |
+
{
|
753 |
+
"type": "github",
|
754 |
+
"url": "https://github.com/sponsors/ai"
|
755 |
+
}
|
756 |
+
],
|
757 |
+
"license": "MIT",
|
758 |
+
"bin": {
|
759 |
+
"nanoid": "bin/nanoid.cjs"
|
760 |
+
},
|
761 |
+
"engines": {
|
762 |
+
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
763 |
+
}
|
764 |
+
},
|
765 |
+
"node_modules/picocolors": {
|
766 |
+
"version": "1.1.1",
|
767 |
+
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
768 |
+
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
|
769 |
+
"dev": true,
|
770 |
+
"license": "ISC"
|
771 |
+
},
|
772 |
+
"node_modules/postcss": {
|
773 |
+
"version": "8.5.3",
|
774 |
+
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz",
|
775 |
+
"integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==",
|
776 |
+
"dev": true,
|
777 |
+
"funding": [
|
778 |
+
{
|
779 |
+
"type": "opencollective",
|
780 |
+
"url": "https://opencollective.com/postcss/"
|
781 |
+
},
|
782 |
+
{
|
783 |
+
"type": "tidelift",
|
784 |
+
"url": "https://tidelift.com/funding/github/npm/postcss"
|
785 |
+
},
|
786 |
+
{
|
787 |
+
"type": "github",
|
788 |
+
"url": "https://github.com/sponsors/ai"
|
789 |
+
}
|
790 |
+
],
|
791 |
+
"license": "MIT",
|
792 |
+
"dependencies": {
|
793 |
+
"nanoid": "^3.3.8",
|
794 |
+
"picocolors": "^1.1.1",
|
795 |
+
"source-map-js": "^1.2.1"
|
796 |
+
},
|
797 |
+
"engines": {
|
798 |
+
"node": "^10 || ^12 || >=14"
|
799 |
+
}
|
800 |
+
},
|
801 |
+
"node_modules/rollup": {
|
802 |
+
"version": "4.40.0",
|
803 |
+
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.40.0.tgz",
|
804 |
+
"integrity": "sha512-Noe455xmA96nnqH5piFtLobsGbCij7Tu+tb3c1vYjNbTkfzGqXqQXG3wJaYXkRZuQ0vEYN4bhwg7QnIrqB5B+w==",
|
805 |
+
"dev": true,
|
806 |
+
"license": "MIT",
|
807 |
+
"dependencies": {
|
808 |
+
"@types/estree": "1.0.7"
|
809 |
+
},
|
810 |
+
"bin": {
|
811 |
+
"rollup": "dist/bin/rollup"
|
812 |
+
},
|
813 |
+
"engines": {
|
814 |
+
"node": ">=18.0.0",
|
815 |
+
"npm": ">=8.0.0"
|
816 |
+
},
|
817 |
+
"optionalDependencies": {
|
818 |
+
"@rollup/rollup-android-arm-eabi": "4.40.0",
|
819 |
+
"@rollup/rollup-android-arm64": "4.40.0",
|
820 |
+
"@rollup/rollup-darwin-arm64": "4.40.0",
|
821 |
+
"@rollup/rollup-darwin-x64": "4.40.0",
|
822 |
+
"@rollup/rollup-freebsd-arm64": "4.40.0",
|
823 |
+
"@rollup/rollup-freebsd-x64": "4.40.0",
|
824 |
+
"@rollup/rollup-linux-arm-gnueabihf": "4.40.0",
|
825 |
+
"@rollup/rollup-linux-arm-musleabihf": "4.40.0",
|
826 |
+
"@rollup/rollup-linux-arm64-gnu": "4.40.0",
|
827 |
+
"@rollup/rollup-linux-arm64-musl": "4.40.0",
|
828 |
+
"@rollup/rollup-linux-loongarch64-gnu": "4.40.0",
|
829 |
+
"@rollup/rollup-linux-powerpc64le-gnu": "4.40.0",
|
830 |
+
"@rollup/rollup-linux-riscv64-gnu": "4.40.0",
|
831 |
+
"@rollup/rollup-linux-riscv64-musl": "4.40.0",
|
832 |
+
"@rollup/rollup-linux-s390x-gnu": "4.40.0",
|
833 |
+
"@rollup/rollup-linux-x64-gnu": "4.40.0",
|
834 |
+
"@rollup/rollup-linux-x64-musl": "4.40.0",
|
835 |
+
"@rollup/rollup-win32-arm64-msvc": "4.40.0",
|
836 |
+
"@rollup/rollup-win32-ia32-msvc": "4.40.0",
|
837 |
+
"@rollup/rollup-win32-x64-msvc": "4.40.0",
|
838 |
+
"fsevents": "~2.3.2"
|
839 |
+
}
|
840 |
+
},
|
841 |
+
"node_modules/source-map-js": {
|
842 |
+
"version": "1.2.1",
|
843 |
+
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
844 |
+
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
|
845 |
+
"dev": true,
|
846 |
+
"license": "BSD-3-Clause",
|
847 |
+
"engines": {
|
848 |
+
"node": ">=0.10.0"
|
849 |
+
}
|
850 |
+
},
|
851 |
+
"node_modules/vite": {
|
852 |
+
"version": "5.4.18",
|
853 |
+
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.18.tgz",
|
854 |
+
"integrity": "sha512-1oDcnEp3lVyHCuQ2YFelM4Alm2o91xNoMncRm1U7S+JdYfYOvbiGZ3/CxGttrOu2M/KcGz7cRC2DoNUA6urmMA==",
|
855 |
+
"dev": true,
|
856 |
+
"license": "MIT",
|
857 |
+
"dependencies": {
|
858 |
+
"esbuild": "^0.21.3",
|
859 |
+
"postcss": "^8.4.43",
|
860 |
+
"rollup": "^4.20.0"
|
861 |
+
},
|
862 |
+
"bin": {
|
863 |
+
"vite": "bin/vite.js"
|
864 |
+
},
|
865 |
+
"engines": {
|
866 |
+
"node": "^18.0.0 || >=20.0.0"
|
867 |
+
},
|
868 |
+
"funding": {
|
869 |
+
"url": "https://github.com/vitejs/vite?sponsor=1"
|
870 |
+
},
|
871 |
+
"optionalDependencies": {
|
872 |
+
"fsevents": "~2.3.3"
|
873 |
+
},
|
874 |
+
"peerDependencies": {
|
875 |
+
"@types/node": "^18.0.0 || >=20.0.0",
|
876 |
+
"less": "*",
|
877 |
+
"lightningcss": "^1.21.0",
|
878 |
+
"sass": "*",
|
879 |
+
"sass-embedded": "*",
|
880 |
+
"stylus": "*",
|
881 |
+
"sugarss": "*",
|
882 |
+
"terser": "^5.4.0"
|
883 |
+
},
|
884 |
+
"peerDependenciesMeta": {
|
885 |
+
"@types/node": {
|
886 |
+
"optional": true
|
887 |
+
},
|
888 |
+
"less": {
|
889 |
+
"optional": true
|
890 |
+
},
|
891 |
+
"lightningcss": {
|
892 |
+
"optional": true
|
893 |
+
},
|
894 |
+
"sass": {
|
895 |
+
"optional": true
|
896 |
+
},
|
897 |
+
"sass-embedded": {
|
898 |
+
"optional": true
|
899 |
+
},
|
900 |
+
"stylus": {
|
901 |
+
"optional": true
|
902 |
+
},
|
903 |
+
"sugarss": {
|
904 |
+
"optional": true
|
905 |
+
},
|
906 |
+
"terser": {
|
907 |
+
"optional": true
|
908 |
+
}
|
909 |
+
}
|
910 |
+
}
|
911 |
+
}
|
912 |
+
}
|
package.json
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"name": "vite-starter",
|
3 |
+
"private": true,
|
4 |
+
"version": "0.0.0",
|
5 |
+
"type": "module",
|
6 |
+
"scripts": {
|
7 |
+
"dev": "vite",
|
8 |
+
"build": "vite build",
|
9 |
+
"preview": "vite preview"
|
10 |
+
},
|
11 |
+
"devDependencies": {
|
12 |
+
"vite": "^5.4.2"
|
13 |
+
}
|
14 |
+
}
|
public/vite.svg
ADDED
|
style.css
ADDED
@@ -0,0 +1,96 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
:root {
|
2 |
+
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
3 |
+
line-height: 1.5;
|
4 |
+
font-weight: 400;
|
5 |
+
|
6 |
+
color-scheme: light dark;
|
7 |
+
color: rgba(255, 255, 255, 0.87);
|
8 |
+
background-color: #242424;
|
9 |
+
|
10 |
+
font-synthesis: none;
|
11 |
+
text-rendering: optimizeLegibility;
|
12 |
+
-webkit-font-smoothing: antialiased;
|
13 |
+
-moz-osx-font-smoothing: grayscale;
|
14 |
+
}
|
15 |
+
|
16 |
+
a {
|
17 |
+
font-weight: 500;
|
18 |
+
color: #646cff;
|
19 |
+
text-decoration: inherit;
|
20 |
+
}
|
21 |
+
a:hover {
|
22 |
+
color: #535bf2;
|
23 |
+
}
|
24 |
+
|
25 |
+
body {
|
26 |
+
margin: 0;
|
27 |
+
display: flex;
|
28 |
+
place-items: center;
|
29 |
+
min-width: 320px;
|
30 |
+
min-height: 100vh;
|
31 |
+
}
|
32 |
+
|
33 |
+
h1 {
|
34 |
+
font-size: 3.2em;
|
35 |
+
line-height: 1.1;
|
36 |
+
}
|
37 |
+
|
38 |
+
#app {
|
39 |
+
max-width: 1280px;
|
40 |
+
margin: 0 auto;
|
41 |
+
padding: 2rem;
|
42 |
+
text-align: center;
|
43 |
+
}
|
44 |
+
|
45 |
+
.logo {
|
46 |
+
height: 6em;
|
47 |
+
padding: 1.5em;
|
48 |
+
will-change: filter;
|
49 |
+
transition: filter 300ms;
|
50 |
+
}
|
51 |
+
.logo:hover {
|
52 |
+
filter: drop-shadow(0 0 2em #646cffaa);
|
53 |
+
}
|
54 |
+
.logo.vanilla:hover {
|
55 |
+
filter: drop-shadow(0 0 2em #f7df1eaa);
|
56 |
+
}
|
57 |
+
|
58 |
+
.card {
|
59 |
+
padding: 2em;
|
60 |
+
}
|
61 |
+
|
62 |
+
.read-the-docs {
|
63 |
+
color: #888;
|
64 |
+
}
|
65 |
+
|
66 |
+
button {
|
67 |
+
border-radius: 8px;
|
68 |
+
border: 1px solid transparent;
|
69 |
+
padding: 0.6em 1.2em;
|
70 |
+
font-size: 1em;
|
71 |
+
font-weight: 500;
|
72 |
+
font-family: inherit;
|
73 |
+
background-color: #1a1a1a;
|
74 |
+
cursor: pointer;
|
75 |
+
transition: border-color 0.25s;
|
76 |
+
}
|
77 |
+
button:hover {
|
78 |
+
border-color: #646cff;
|
79 |
+
}
|
80 |
+
button:focus,
|
81 |
+
button:focus-visible {
|
82 |
+
outline: 4px auto -webkit-focus-ring-color;
|
83 |
+
}
|
84 |
+
|
85 |
+
@media (prefers-color-scheme: light) {
|
86 |
+
:root {
|
87 |
+
color: #213547;
|
88 |
+
background-color: #ffffff;
|
89 |
+
}
|
90 |
+
a:hover {
|
91 |
+
color: #747bff;
|
92 |
+
}
|
93 |
+
button {
|
94 |
+
background-color: #f9f9f9;
|
95 |
+
}
|
96 |
+
}
|