diff --git a/404.html b/404.html
deleted file mode 100644
index abf9404f..00000000
--- a/404.html
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
-
- Page Not Found :(
-
-
-
-
- 4
4
- Oops! Page not found.
- We couldn't find the page you requested. It might be unavailable at the moment or have a different URL.
- Return to Home
-
-
\ No newline at end of file
diff --git a/Documentation/PROJECT_STRUCTURE.md b/Documentation/PROJECT_STRUCTURE.md
index 901308b5..bda663ad 100644
--- a/Documentation/PROJECT_STRUCTURE.md
+++ b/Documentation/PROJECT_STRUCTURE.md
@@ -2,7 +2,13 @@
```
-├── 404.html
+├── LICENSE.md
+├── README.md
+├── SECURITY.md
+├── appconfig
+├── documentation.html
+├── index.html
+├── sitemap.xml
├── Documentation/
│ ├── PROJECT_STRUCTURE.md
│ ├── contributing.md
@@ -16,15 +22,8 @@
│ ├── repo_structure.txt
│ └── styles/
│ └── sitemap.xsl
-├── LICENSE.md
-├── README.md
-├── SECURITY.md
-├── appconfig
-├── documentation.html
-├── index.html
├── installation/
│ └── requirements.txt
-├── sitemap.xml
├── software/
│ ├── __pycache__/
│ │ ├── dataVisualization.cpython-311.pyc
@@ -100,7 +99,14 @@
│ ├── report.py
│ └── tempCodeRunnerFile.py
└── website/
- ├── pages/
+ ├── main.py
+ ├── routes/
+ ├── models/
+ ├── schema/
+ ├── templates/
+ | ├── index.html
+ | ├── documentation.html
+ | ├── 404.html
│ ├── contributor.html
│ ├── license.html
│ ├── login.html
diff --git a/README.md b/README.md
index 311d3ab0..c3de7028 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
# Dataverse
-
+
###### Data Visualisation Software & Finance Tracker
@@ -89,11 +89,11 @@ Software Home Page
Visualised Data
-
+
Stored Data
-
+
@@ -154,20 +154,21 @@ V. Install MySQL if you don't have it already from [here](https://dev.mysql.com/
> [!IMPORTANT]
> Change the values of `DB_HOST`, `DB_USER` and `DB_PASSWORD` in [software/db_config.py](software/db_config.py) file according to your MySQL account.
-VI. Run the application:
+VI (a). To run the application:
> ```
-> python software/main.py
+> python software\main.py
> ```
-VII. To Run `index.html` (For Website Development)
+VI (b). To run the website:
-1. Install the **Go Live** extension in VS Code.
-2. Open the `index.html` file in VS Code.
-3. Click on the **Go Live** button in the bottom-right corner of VS Code.
+> ```
+> cd website
+> uvicorn main:app --reload
+> ```
> The default URL will be:
-> `http://localhost:5500/Dataverse/index.html`
+> `http://127.0.0.1:8000`
Now, the software should run smoothly with no errors, feel free to use the software and don't forget to give feedback on [Dataverse's website](https://multiverse-dataverse.netlify.app/)!
diff --git a/index.html b/index.html
deleted file mode 100644
index b756b856..00000000
--- a/index.html
+++ /dev/null
@@ -1,352 +0,0 @@
-
-
-
-
-
-
- Dataverse
-
-
-
-
-
-
-
-
-
-
-
-
-
- Your browser does not support the
- video tag.
-
-
-
-
-
-
-
-
-
- Login
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
An Open-Source Software (OSS) that allows organizing, analyzing and visualizing data,
- providing flexible tools for financial tracking and customized chart creation.
-
-
The adjoining map shows people who are using or contributing to Dataverse.
-
Get
- Dataverse
-
-
-
-
-
-
-
-
-
-
So, What does this Software do?
-
Visualise Data!
-
Easily transform raw data into visually appealing charts such as bar graphs, pie charts,
- and
- line graphs. It also supports advanced data visualisation techniques like heatmaps, Radar charts, 3D
- Surface Plots, etc..
-
- You can also download the generated plots or save the data for later use.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Track Finances!
-
Manage your finances by providing data such as income, expense, investment, etc. and get
- useful results such as visualization of data, extrapolated data, max expenditure, etc.. Also, the
- software automatically stores data with a timestamp.
-
-
-
-
-
Here are some examples of what you can do with Dataverse
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Want to contribute to this Project?
-
-
-
-
-
-
Technologies Used
-
-
-
-
As this is an open-source project, contributions are always welcome. Whether you're
- interested in adding new features, fixing bugs, or improving documentation, your contributions are
- valuable. You can contribute to the project by visiting the link to the GitHub repository provided
- below. Join me in making Dataverse even better for everyone!
-
- Contribute
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/installation/requirements.txt b/installation/requirements.txt
index ee35841c..19410a88 100644
--- a/installation/requirements.txt
+++ b/installation/requirements.txt
@@ -1,16 +1,36 @@
-PIL
-time
+annotated-types
+anyio
+click
+colorama
+contourpy
+customtkinter
+cycler
+darkdetect
+dnspython
+fastapi
+fonttools
+h11
+idna
+Jinja2
+kiwisolver
+MarkupSafe
+matplotlib>=3.2,<3.11 # Adding version range for compatibility
+motor
+mysql-connector
+mysql-connector-python
numpy
-ctypes
-tkinter
-datetime
+packaging
+pillow
+pydantic
+pydantic_core
+pymongo
+pyparsing
+python-dateutil
+python-dotenv
+six
+sniffio
+starlette
tabulate
-functools
-webbrowser
-matplotlib
-customtkinter
-mysql.connector
-matplotlib.pyplot
-matplotlib.gridspec
-matplotlib.widgets
-mpl_toolkits.mplot3d
\ No newline at end of file
+typing_extensions
+uvicorn
+python-multipart
\ No newline at end of file
diff --git a/software/__pycache__/dataVisualization.cpython-311.pyc b/software/__pycache__/dataVisualization.cpython-311.pyc
deleted file mode 100644
index 5fd2f71b..00000000
Binary files a/software/__pycache__/dataVisualization.cpython-311.pyc and /dev/null differ
diff --git a/software/__pycache__/db_config.cpython-312.pyc b/software/__pycache__/db_config.cpython-312.pyc
deleted file mode 100644
index b214bdce..00000000
Binary files a/software/__pycache__/db_config.cpython-312.pyc and /dev/null differ
diff --git a/software/__pycache__/financeTracker.cpython-311.pyc b/software/__pycache__/financeTracker.cpython-311.pyc
deleted file mode 100644
index 5eddb9ef..00000000
Binary files a/software/__pycache__/financeTracker.cpython-311.pyc and /dev/null differ
diff --git a/software/__pycache__/functions.cpython-311.pyc b/software/__pycache__/functions.cpython-311.pyc
deleted file mode 100644
index db5778c8..00000000
Binary files a/software/__pycache__/functions.cpython-311.pyc and /dev/null differ
diff --git a/software/__pycache__/main.cpython-311.pyc b/software/__pycache__/main.cpython-311.pyc
deleted file mode 100644
index a349598f..00000000
Binary files a/software/__pycache__/main.cpython-311.pyc and /dev/null differ
diff --git a/software/__pycache__/mainGUI.cpython-311.pyc b/software/__pycache__/mainGUI.cpython-311.pyc
deleted file mode 100644
index 4b011131..00000000
Binary files a/software/__pycache__/mainGUI.cpython-311.pyc and /dev/null differ
diff --git a/software/__pycache__/manage_data.cpython-312.pyc b/software/__pycache__/manage_data.cpython-312.pyc
deleted file mode 100644
index cec07004..00000000
Binary files a/software/__pycache__/manage_data.cpython-312.pyc and /dev/null differ
diff --git a/software/__pycache__/plot.cpython-311.pyc b/software/__pycache__/plot.cpython-311.pyc
deleted file mode 100644
index 7ca2d57a..00000000
Binary files a/software/__pycache__/plot.cpython-311.pyc and /dev/null differ
diff --git a/software/__pycache__/report.cpython-311.pyc b/software/__pycache__/report.cpython-311.pyc
deleted file mode 100644
index 91d4bd19..00000000
Binary files a/software/__pycache__/report.cpython-311.pyc and /dev/null differ
diff --git a/website/main.py b/website/main.py
new file mode 100644
index 00000000..ef2cb134
--- /dev/null
+++ b/website/main.py
@@ -0,0 +1,94 @@
+from fastapi import FastAPI, Request
+from fastapi.responses import HTMLResponse
+from pathlib import Path
+from fastapi.staticfiles import StaticFiles
+from motor.motor_asyncio import AsyncIOMotorClient
+from fastapi.templating import Jinja2Templates
+from contextlib import asynccontextmanager
+from dotenv import load_dotenv
+import os
+from routes.feedback import router as feedback_router
+
+# Load .env file
+load_dotenv()
+
+# Use lifespan to handle startup and shutdown events
+@asynccontextmanager
+async def lifespan(app: FastAPI):
+ # On startup
+ try:
+ # Try a simple query to check the connection
+ await db.command("ping")
+ print("MongoDB connected successfully!")
+ yield
+ except Exception as e:
+ print(f"Error connecting to MongoDB: {e}")
+ raise e
+ finally:
+ # On shutdown
+ client.close() # Clean up the MongoDB client
+
+# Create FastAPI app and pass lifespan
+app = FastAPI(lifespan=lifespan)
+
+# Serve static files
+app.mount("/static", StaticFiles(directory="../"), name="static")
+app.mount("/web_images", StaticFiles(directory="web_images"), name="web_images")
+app.mount("/styles", StaticFiles(directory="styles"), name="styles")
+app.mount("/scripts", StaticFiles(directory="scripts"), name="scripts")
+app.mount("/software", StaticFiles(directory="../software"), name="software")
+app.mount("/Documentation", StaticFiles(directory="../Documentation"), name="Documentation")
+
+# Set up Jinja2 templates for dynamic HTML rendering
+templates = Jinja2Templates(directory="templates/")
+
+# MongoDB setup
+MONGODB_URL = os.getenv("MONGODB_URL")
+client = AsyncIOMotorClient(MONGODB_URL)
+db = client.Dataverse
+
+# Collections
+feedback_collection = db["feedbacks"]
+
+# Include Routers
+app.include_router(feedback_router)
+
+@app.get("/", response_class=HTMLResponse)
+def read_root(request: Request):
+ return templates.TemplateResponse("index.html", {"request": request})
+
+@app.get("/login", response_class=HTMLResponse)
+def documentation(request: Request):
+ return templates.TemplateResponse("login.html", {"request": request})
+
+@app.get("/signup", response_class=HTMLResponse)
+def documentation(request: Request):
+ return templates.TemplateResponse("signup.html", {"request": request})
+
+@app.get("/documentation", response_class=HTMLResponse)
+def documentation(request: Request):
+ return templates.TemplateResponse("documentation.html", {"request": request})
+
+@app.get("/versions", response_class=HTMLResponse)
+def versions(request: Request):
+ return templates.TemplateResponse("versions.html", {"request": request})
+
+@app.get("/support", response_class=HTMLResponse)
+def support(request: Request):
+ return templates.TemplateResponse("support.html", {"request": request})
+
+@app.get("/contributor", response_class=HTMLResponse)
+def contributor(request: Request):
+ return templates.TemplateResponse("contributor.html", {"request": request})
+
+@app.get("/reviews", response_class=HTMLResponse)
+def reviews(request: Request):
+ return templates.TemplateResponse("reviews.html", {"request": request})
+
+@app.get("/license", response_class=HTMLResponse)
+def license(request: Request):
+ return templates.TemplateResponse("license.html", {"request": request})
+
+@app.get("/404", response_class=HTMLResponse)
+def not_found(request: Request):
+ return templates.TemplateResponse("404.html", {"request": request})
\ No newline at end of file
diff --git a/website/models/feedback.py b/website/models/feedback.py
new file mode 100644
index 00000000..8dec6bd5
--- /dev/null
+++ b/website/models/feedback.py
@@ -0,0 +1,6 @@
+from pydantic import BaseModel
+class Feedback(BaseModel):
+ Name: str
+ Email: str
+ Message: str
+ Rating: int
\ No newline at end of file
diff --git a/website/pages/support.html b/website/pages/support.html
deleted file mode 100644
index 4a01e67e..00000000
--- a/website/pages/support.html
+++ /dev/null
@@ -1,215 +0,0 @@
-
-
-
-
-
-
- Dataverse | Support
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Need Help?
-
Try asking Infinity
-
-
-
-
-
-
-
Frequently Asked Questions
-
- What is Dataverse?
- Dataverse is an open-source software platform designed for tracking finances, visualizing data,
- and integrating database management. It provides powerful tools for data visualization and
- storage.
-
-
- What features does Dataverse offer?
- Dataverse offers features such as data visualization, financial tracking, chart generation, and
- secure storage. It also allows users to download generated charts and manage data for future
- use.
-
-
- Is Dataverse free to use?
- Yes, Dataverse is open-source and free to use. You can contribute to its development on GitHub.
-
-
-
- How can I contribute to Dataverse?
- You can contribute by visiting the official Dataverse repository on GitHub and following the
- contribution guidelines. We welcome developers, testers, and documentation writers.
-
-
- Where can I get support for using Dataverse?
- Support is available through our GitHub discussions page, community forums, and documentation.
- Feel free to reach out for help!
-
-
-
-
-
Encountered an Issue?
-
Report Issue
-
-
-
-
-
-
Support the Development of Dataverse
- As an open-source initiative, we depend on community support to sustain and enhance the project. Your
- contributions will help us:
-
- Develop New Features
- Improve User Experience
- Maintain the Platform
- Foster Community Growth
- Develop More Such Software
-
-
-
How You Can Support
-
- Contribute Code: If you're a developer, join us on GitHub to improve the platform.
-
Contribute
-
-
-
- Sponsor Us: If you sponsor me, I'll be able to do more of what I'm already
- doing, better, and for you, the community, all while remaining open-source!
-
GitHub
- Sponsors
-
-
-
-
-
-
-
-
- Go To Home
-
-
-
diff --git a/website/routes/feedback.py b/website/routes/feedback.py
new file mode 100644
index 00000000..fec2a017
--- /dev/null
+++ b/website/routes/feedback.py
@@ -0,0 +1,17 @@
+from fastapi import APIRouter, Form
+from schema.feedback import submit_feedback
+from models.feedback import Feedback
+
+router = APIRouter()
+
+@router.post("/submit_feedback")
+async def submit_feedback_route(
+ Name: str = Form(...),
+ Email: str = Form(...),
+ Message: str = Form(...),
+ Rating: int = Form(...),
+):
+ # Convert the raw data into a Pydantic model
+ feedback = Feedback(Name=Name, Email=Email, Message=Message, Rating=Rating)
+
+ return await submit_feedback(feedback)
\ No newline at end of file
diff --git a/website/schema/feedback.py b/website/schema/feedback.py
new file mode 100644
index 00000000..33c15caf
--- /dev/null
+++ b/website/schema/feedback.py
@@ -0,0 +1,21 @@
+from fastapi import HTTPException
+from models.feedback import Feedback
+
+async def submit_feedback(feedback: Feedback):
+ try:
+ from main import feedback_collection
+
+ feedback_data = feedback.dict() # Convert Pydantic model to dictionary
+
+ result = await feedback_collection.insert_one(feedback_data) # Insert the feedback data into MongoDB
+
+ # Check if insertion was successful and return a response
+ if result.inserted_id:
+ print(f"Inserted feedback with ID: {result.inserted_id}")
+ return {"success": True, "message": "Feedback submitted successfully."}
+ else:
+ raise HTTPException(status_code=400, detail="Failed to insert feedback.")
+
+ except Exception as e:
+ print(f"Error: {e}")
+ raise HTTPException(status_code=500, detail="There was an error processing your feedback.")
\ No newline at end of file
diff --git a/website/scripts/beautifyReviews.js b/website/scripts/beautifyReviews.js
index 28ae3f2b..9d6a080b 100644
--- a/website/scripts/beautifyReviews.js
+++ b/website/scripts/beautifyReviews.js
@@ -1,11 +1,11 @@
-fetch('../scripts/reviews.json')
- .then(response => response.json())
- .then(data => {
- const averageRating = calculateAverageRating(data);
- displayAverageRating(averageRating);
- displayReviews(data);
- })
- .catch(error => console.error("Error loading reviews:", error));
+fetch("/scripts/reviews.json")
+ .then((response) => response.json())
+ .then((data) => {
+ const averageRating = calculateAverageRating(data);
+ displayAverageRating(averageRating);
+ displayReviews(data);
+ })
+ .catch((error) => console.error("Error loading reviews:", error));
// Function to calculate the average rating
function calculateAverageRating(reviews) {
diff --git a/website/scripts/script.js b/website/scripts/script.js
index 13da2f33..b8f9b6c4 100644
--- a/website/scripts/script.js
+++ b/website/scripts/script.js
@@ -3,101 +3,130 @@ import { showModal, closeModal, attachToWindow } from "./sharedUtilities.js";
var windowFunctions = [];
// Array of city names
-var cities = ["Pune", "Moradabad", "Dehradun", "Rampur", "Delhi", "Coimbatore", "Riyadh", "Ahmedabad", "Kolkata", "Mumbai", "Jorhat", "Arrah", "Bhopal", "Bengalore", "Secunderabad", "Ludhiana", "Nagpur", "Lucknow", "Gorakhpur", "Bhilai", "Kanpur", "Panaji","Dhamtari","Vijaywada","Ujjain","Sydney"];
+var cities = [
+ "Pune",
+ "Moradabad",
+ "Dehradun",
+ "Rampur",
+ "Delhi",
+ "Coimbatore",
+ "Riyadh",
+ "Ahmedabad",
+ "Kolkata",
+ "Mumbai",
+ "Jorhat",
+ "Arrah",
+ "Bhopal",
+ "Bengalore",
+ "Secunderabad",
+ "Ludhiana",
+ "Nagpur",
+ "Lucknow",
+ "Gorakhpur",
+ "Bhilai",
+ "Kanpur",
+ "Panaji",
+ "Dhamtari",
+ "Vijaywada",
+ "Ujjain",
+ "Sydney",
+];
try {
- var map = L.map('map', {
+ var map = L.map("map", {
center: [22.7937, 77.9629],
zoom: 4,
- zoomControl: false
- });
+ zoomControl: false,
+ });
- // Add OpenStreetMap tile layer
- L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
- attribution: '© OpenStreetMap contributors'
+ // Add OpenStreetMap tile layer
+ L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
+ attribution:
+ '© OpenStreetMap contributors',
}).addTo(map);
var redIcon = L.icon({
- iconUrl: 'https://img1.picmix.com/output/stamp/normal/2/5/4/3/873452_376bb.png',
+ iconUrl:
+ "https://img1.picmix.com/output/stamp/normal/2/5/4/3/873452_376bb.png",
iconSize: [20, 20],
iconAnchor: [12, 12],
popupAnchor: [1, -34],
- shadowSize: [41, 41]
+ shadowSize: [41, 41],
});
-} catch(e) {
+} catch (e) {
console.error(e);
}
// Your OpenCage API Key here
-const OPENCAGE_API_KEY = '3f55c6e93c2c4b19ae45f1fd5db12cfc';
+const OPENCAGE_API_KEY = "3f55c6e93c2c4b19ae45f1fd5db12cfc";
// Function to get coordinates for a city and add a marker using OpenCage API
async function addMarker(city) {
- var url = `https://api.opencagedata.com/geocode/v1/json?q=${city}&key=${OPENCAGE_API_KEY}`;
-
- try {
- const response = await fetch(url);
-
- if (!response.ok) throw new Error(`Network response was not ok: ${response.statusText}`);
-
- const data = await response.json();
-
- if (data.results.length > 0) {
- const lat = data.results[0].geometry.lat;
- const lon = data.results[0].geometry.lng;
- L.marker([lat, lon], { icon: redIcon }).addTo(map)
- .bindPopup(city);
- } else {
- console.log("No results found for " + city);
- }
- } catch (error) {
- console.error("Error fetching coordinates for " + city + ": " + error);
+ var url = `https://api.opencagedata.com/geocode/v1/json?q=${city}&key=${OPENCAGE_API_KEY}`;
+
+ try {
+ const response = await fetch(url);
+
+ if (!response.ok)
+ throw new Error(`Network response was not ok: ${response.statusText}`);
+
+ const data = await response.json();
+
+ if (data.results.length > 0) {
+ const lat = data.results[0].geometry.lat;
+ const lon = data.results[0].geometry.lng;
+ L.marker([lat, lon], { icon: redIcon }).addTo(map).bindPopup(city);
+ } else {
+ console.log("No results found for " + city);
}
+ } catch (error) {
+ console.error("Error fetching coordinates for " + city + ": " + error);
+ }
}
// Function to add markers with a delay to respect API limits
async function addMarkersWithDelay(cities) {
- for (let i = 0; i < cities.length; i++) {
- await addMarker(cities[i]);
- await new Promise(resolve => setTimeout(resolve, 1000)); // 1-second delay between requests
- }
+ for (let i = 0; i < cities.length; i++) {
+ await addMarker(cities[i]);
+ await new Promise((resolve) => setTimeout(resolve, 1000)); // 1-second delay between requests
+ }
}
// Call the function to add markers
addMarkersWithDelay(cities);
-
// /preloader js styling and other stuff needed for preload
-window.addEventListener('DOMContentLoaded', () => {
+window.addEventListener("DOMContentLoaded", () => {
// Hide the loader after 3 seconds
setTimeout(() => {
- const loader = document.getElementById('video-loader');
- if(loader) {
- loader.style.display = 'none';
- }
+ const loader = document.getElementById("video-loader");
+ if (loader) {
+ loader.style.display = "none";
+ }
- displayCopyright();
+ displayCopyright();
}, 3000);
attachToWindow(windowFunctions);
});
function topFunction() {
- document.body.scrollTop = 0;
- document.documentElement.scrollTop = 0;
+ document.body.scrollTop = 0;
+ document.documentElement.scrollTop = 0;
}
windowFunctions.push(topFunction);
function changeCss() {
- var top = document.getElementById("top");
- var scroll_icon = document.getElementById("scroll_icon");
- if(scroll_icon) {
- (this.scrollY > 30) ? top.style.opacity = 1 : top.style.opacity = 0;
- (this.scrollY > 0) ? scroll_icon.style.opacity = 0 : scroll_icon.style.opacity = 1;
- }
+ var top = document.getElementById("top");
+ var scroll_icon = document.getElementById("scroll_icon");
+ if (scroll_icon) {
+ this.scrollY > 30 ? (top.style.opacity = 1) : (top.style.opacity = 0);
+ this.scrollY > 0
+ ? (scroll_icon.style.opacity = 0)
+ : (scroll_icon.style.opacity = 1);
+ }
}
window.addEventListener("scroll", changeCss, false);
-
console.log("Tejas' Codes :)");
var l1 = document.getElementById("l1");
@@ -121,57 +150,43 @@ var download = document.getElementById("download_btn");
const lightButton = document.getElementById("lightButton");
const darkButton = document.getElementById("darkButton");
const technologies = document.getElementById("technologies");
-var footer=document.getElementById("footer");
-var links=document.getElementById("linksTejas");
-var endLogo=document.getElementById("end-logo");
-
+var footer = document.getElementById("footer");
+var links = document.getElementById("linksTejas");
+var endLogo = document.getElementById("end-logo");
+var feedbackForm = document.getElementById("feedback-form");
let lastScrollTop = 0;
const navbar = document.getElementById("navbar");
-window.addEventListener('scroll', () => {
+window.addEventListener("scroll", () => {
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
if (scrollTop > lastScrollTop) {
// Scroll down
- navbar.style.top = '-60px';
- burger.style.top = '-60px';
- lines.style.top = '-60px';
- cross.style.top = '-60px';
+ navbar.style.top = "-60px";
+ burger.style.top = "-60px";
+ lines.style.top = "-60px";
+ cross.style.top = "-60px";
} else {
// Scroll up
- navbar.style.top = '0';
- burger.style.top = '10px';
- lines.style.top = '10px';
- cross.style.top = '10px';
+ navbar.style.top = "0";
+ burger.style.top = "10px";
+ lines.style.top = "10px";
+ cross.style.top = "10px";
}
lastScrollTop = scrollTop;
});
-window.onload = function() {
- let feedbackField;
- if(document.forms['feedback-form']) {
- feedbackField = document.forms['feedback-form']['Message'];
-
- feedbackField.addEventListener('focus', () => {
- checkFeedbackLength(feedbackField);
- })
-
- feedbackField.addEventListener('blur', () => {
- document.getElementById('feedbackError').style.opacity = '0%';
- })
- }
-
-}
-
let lastScroll = 0;
function progress() {
var scroll = this.scrollY;
- var scrollHeight = document.documentElement.scrollHeight - document.documentElement.clientHeight;
+ var scrollHeight =
+ document.documentElement.scrollHeight -
+ document.documentElement.clientHeight;
var percent = Math.round((scroll / scrollHeight) * 100);
- document.getElementById("progress_bar").style.width = percent + 'vw';
-};
+ document.getElementById("progress_bar").style.width = percent + "vw";
+}
window.addEventListener("scroll", progress);
@@ -199,94 +214,114 @@ function hide() {
}
windowFunctions.push(hide);
-
function updateIndicator(button) {
const adjustment = (button.offsetHeight - indicator.offsetHeight) / 2;
indicator.style.top = `${button.offsetTop + adjustment}px`;
- const currentTheme = localStorage.getItem('theme');
- if (currentTheme === 'light') {
- indicator.style.backgroundImage = "radial-gradient(circle, rgba(0, 0, 0, 0.8), rgba(0, 0, 0, 0))"; // Black glow for light mode
- // indicator.style.boxShadow = "0 0 5px 3px rgba(0, 0, 0, 0.7)"; // Subtle black glow
+ const currentTheme = localStorage.getItem("theme");
+ if (currentTheme === "light") {
+ indicator.style.backgroundImage =
+ "radial-gradient(circle, rgba(0, 0, 0, 0.8), rgba(0, 0, 0, 0))"; // Black glow for light mode
+ // indicator.style.boxShadow = "0 0 5px 3px rgba(0, 0, 0, 0.7)"; // Subtle black glow
} else {
- indicator.style.backgroundImage = "radial-gradient(circle, rgba(255, 255, 255, 0.7), rgba(0, 0, 0, 0))"; // White glow for dark mode
- // indicator.style.boxShadow = "0 0 5px 3px rgba(255, 255, 255, 0.7)"; // Subtle white glow
+ indicator.style.backgroundImage =
+ "radial-gradient(circle, rgba(255, 255, 255, 0.7), rgba(0, 0, 0, 0))"; // White glow for dark mode
+ // indicator.style.boxShadow = "0 0 5px 3px rgba(255, 255, 255, 0.7)"; // Subtle white glow
}
}
windowFunctions.push(updateIndicator);
function light(flag) {
- localStorage.setItem('theme', 'light');
- document.body.classList.remove('dark-mode');
- document.body.classList.add('light-mode');
- if(document.getElementById("map") && tags && contribute && shadow && technologies) {
+ localStorage.setItem("theme", "light");
+ document.body.classList.remove("dark-mode");
+ document.body.classList.add("light-mode");
+ if (
+ document.getElementById("map") &&
+ tags &&
+ contribute &&
+ shadow &&
+ technologies
+ ) {
document.getElementById("map").style.filter = "none";
document.getElementById("map").style.zIndex = 0;
tags.style.borderColor = "black";
tags.style.backgroundColor = "#00000000";
- contribute.style.filter="invert(1)";
- shadow.style.backgroundImage = "linear-gradient(115deg, #00000000,#f9f9f9,#00000000)";
- technologies.style.border="1px solid #000000";
+ contribute.style.filter = "invert(1)";
+ shadow.style.backgroundImage =
+ "linear-gradient(115deg, #00000000,#f9f9f9,#00000000)";
+ technologies.style.border = "1px solid #000000";
/*footer.style.backgroundColor="#ffffff";
footer.style.color="#000000";
links.style.backgroundColor="#ffffff";
links.style.color="#000000";*/
- footer.style.filter="invert(1)";
- links.style.filter="invert(1)";
- endLogo.style.filter="invert(1)";
+ footer.style.filter = "invert(1)";
+ links.style.filter = "invert(1)";
+ endLogo.style.filter = "invert(1)";
}
- indicator.style.backgroundImage = "radial-gradient(rgba(0,0,0, 0.608),#00000000,#00000000)";
+ indicator.style.backgroundImage =
+ "radial-gradient(rgba(0,0,0, 0.608),#00000000,#00000000)";
const lightButton = document.getElementById("lightButton");
updateIndicator(lightButton); // Update the indicator position and style for the light button
}
windowFunctions.push(light);
function dark(flag) {
- if(document.getElementById("map") && tags && contribute && shadow && technologies) {
- document.getElementById("map").style.filter = "invert(1) hue-rotate(180deg) brightness(1.7)";
+ if (
+ document.getElementById("map") &&
+ tags &&
+ contribute &&
+ shadow &&
+ technologies
+ ) {
+ document.getElementById("map").style.filter =
+ "invert(1) hue-rotate(180deg) brightness(1.7)";
tags.style.borderColor = "rgba(255, 255, 255, 0.323)";
tags.style.backgroundColor = "#00000000";
- shadow.style.backgroundImage = "linear-gradient(115deg, #00000000,#000000d4,#00000000)";
- contribute.style.filter="invert(0)";
- technologies.style.border="1px solid #ffffff44";
+ shadow.style.backgroundImage =
+ "linear-gradient(115deg, #00000000,#000000d4,#00000000)";
+ contribute.style.filter = "invert(0)";
+ technologies.style.border = "1px solid #ffffff44";
/*footer.style.backgroundColor="#000000";
footer.style.color="#ffffff";
links.style.backgroundColor="#000000";
links.style.color="#ffffff";*/
- footer.style.filter="invert(0)";
- links.style.filter="invert(0)";
- endLogo.style.filter="invert(0)";
+ footer.style.filter = "invert(0)";
+ links.style.filter = "invert(0)";
+ endLogo.style.filter = "invert(0)";
}
- localStorage.setItem('theme', 'dark');
- indicator.style.backgroundImage = "radial-gradient(rgba(255,255,255, 0.608),#00000000,#00000000)";
- document.body.classList.remove('light-mode');
- document.body.classList.add('dark-mode');
+ localStorage.setItem("theme", "dark");
+ indicator.style.backgroundImage =
+ "radial-gradient(rgba(255,255,255, 0.608),#00000000,#00000000)";
+ document.body.classList.remove("light-mode");
+ document.body.classList.add("dark-mode");
const darkButton = document.getElementById("darkButton");
updateIndicator(darkButton); // Update the indicator position and style for the dark button
-
}
windowFunctions.push(dark);
function systemDefault() {
- const theme = localStorage.getItem('theme');
+ const theme = localStorage.getItem("theme");
const defaultButton = document.getElementById("defaultButton");
- if (theme === 'light') {
- light(true);
- updateIndicator(document.getElementById("lightButton")); // Ensure the indicator moves to the light button
- } else if (theme === 'dark') {
- dark(true);
- updateIndicator(document.getElementById("darkButton")); // Ensure the indicator moves to the dark button
+ if (theme === "light") {
+ light(true);
+ updateIndicator(document.getElementById("lightButton")); // Ensure the indicator moves to the light button
+ } else if (theme === "dark") {
+ dark(true);
+ updateIndicator(document.getElementById("darkButton")); // Ensure the indicator moves to the dark button
} else {
- // Fallback based on system preference
- if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
- dark(true);
- updateIndicator(document.getElementById("darkButton")); // If system preference is dark
- } else {
- light(true);
- updateIndicator(document.getElementById("lightButton")); // If system preference is light
- }
+ // Fallback based on system preference
+ if (
+ window.matchMedia &&
+ window.matchMedia("(prefers-color-scheme: dark)").matches
+ ) {
+ dark(true);
+ updateIndicator(document.getElementById("darkButton")); // If system preference is dark
+ } else {
+ light(true);
+ updateIndicator(document.getElementById("lightButton")); // If system preference is light
+ }
}
// Move indicator to the default button when explicitly selected
@@ -308,7 +343,6 @@ document.getElementById("defaultButton").addEventListener("click", () => {
updateIndicator(document.getElementById("defaultButton"));
});
-
let scrollSpeed = 2;
let currentSpeed = scrollSpeed;
let autoScroll = true;
@@ -316,50 +350,53 @@ let scrollTimeout;
// Function to scroll the 'examples' and 'examples2' div automatically
function autoScrollExamples() {
- if(examples, examples2) {
+ if ((examples, examples2)) {
if (autoScroll) {
examples.scrollLeft += currentSpeed;
examples2.scrollLeft += currentSpeed * 1.2;
-
+
// Looping the scroll
if (examples.scrollLeft + examples.clientWidth >= examples.scrollWidth) {
- examples.scrollLeft = 0;
+ examples.scrollLeft = 0;
}
- if (examples2.scrollLeft + examples2.clientWidth >= examples2.scrollWidth) {
- examples2.scrollLeft = 0;
+ if (
+ examples2.scrollLeft + examples2.clientWidth >=
+ examples2.scrollWidth
+ ) {
+ examples2.scrollLeft = 0;
}
}
}
}
-
setInterval(autoScrollExamples, 30);
// Smoothly adjust scroll speed
const adjustSpeed = (targetSpeed) => {
- clearInterval(scrollTimeout);
- scrollTimeout = setInterval(() => {
- if (currentSpeed !== targetSpeed) {
- currentSpeed += (targetSpeed > currentSpeed ? 0.1 : -0.3);
- currentSpeed = Math.abs(currentSpeed - targetSpeed) < 0.1 ? targetSpeed : currentSpeed;
- } else {
- clearInterval(scrollTimeout);
- }
- }, 30);
+ clearInterval(scrollTimeout);
+ scrollTimeout = setInterval(() => {
+ if (currentSpeed !== targetSpeed) {
+ currentSpeed += targetSpeed > currentSpeed ? 0.1 : -0.3;
+ currentSpeed =
+ Math.abs(currentSpeed - targetSpeed) < 0.1 ? targetSpeed : currentSpeed;
+ } else {
+ clearInterval(scrollTimeout);
+ }
+ }, 30);
};
// Hovering behavior with smooth stop/resume
const stopAutoScroll = () => {
- autoScroll = false;
- adjustSpeed(0);
+ autoScroll = false;
+ adjustSpeed(0);
};
const startAutoScroll = () => {
- autoScroll = true;
- adjustSpeed(scrollSpeed);
+ autoScroll = true;
+ adjustSpeed(scrollSpeed);
};
-if(examples, examples2) {
+if ((examples, examples2)) {
examples.addEventListener("mouseenter", stopAutoScroll);
examples.addEventListener("mouseleave", startAutoScroll);
examples2.addEventListener("mouseenter", stopAutoScroll);
@@ -371,93 +408,131 @@ window.addEventListener("scroll", progress);
/*CHANGING DIRECTION OF AEROPLANE*/
function updateAngle() {
- let randomAngle = Math.floor(Math.random() * 360) + 'deg';
- document.documentElement.style.setProperty('--angle', randomAngle);
+ let randomAngle = Math.floor(Math.random() * 360) + "deg";
+ document.documentElement.style.setProperty("--angle", randomAngle);
}
setInterval(updateAngle, 10000);
-// FORM VALIDATING FUNCTION
-function validateForm() {
- const form = document.getElementById('feedback-form');
+/*VALIDATE FORM AND CALL BACKEND*/
+window.onload = function () {
+ let feedbackField;
+ if (document.forms["feedback-form"]) {
+ feedbackField = document.forms["feedback-form"]["Message"];
+
+ feedbackField.addEventListener("focus", () => {
+ checkFeedbackLength(feedbackField);
+ });
+
+ feedbackField.addEventListener("blur", () => {
+ document.getElementById("feedbackError").style.opacity = "0%";
+ });
+ }
+};
+
+function validateForm(event) {
+ event.preventDefault(); // Prevent form from submitting by default
+
const nameInput = document.querySelector('[name="Name"]');
const emailInput = document.querySelector('[name="Email"]');
const messageInput = document.querySelector('textarea[name="Message"]');
- const rating = document.querySelector('[name=rating]:checked');
+ const rating = document.querySelector('[name="rating"]:checked'); // Get the checked rating
- if (nameInput.value === '') {
- alert('Please enter your name.');
- return false;
+ if (nameInput.value === "") {
+ alert("Please enter your name.");
+ return false;
}
-
+
if (!isValidEmail(emailInput.value)) {
- alert('Please enter a valid email address.');
+ alert("Please enter a valid email address.");
return false;
}
-
- if (messageInput.value === '') {
- alert('Please enter your message.');
- return false;
+
+ if (messageInput.value === "") {
+ alert("Please enter your message.");
+ return false;
}
- if (rating === false || rating === null) {
+
+ if (!rating) {
alert("Please select a rating.");
- return false;
- }
+ return false;
+ }
- if(!checkFeedbackLength(messageInput)) {
+ if (!checkFeedbackLength(messageInput)) {
return false;
}
-
- const formData = {
- Name: nameInput.value,
- Email: emailInput.value,
- Message: messageInput.value
- };
- localStorage.setItem('reviewData', JSON.stringify(formData));
-
- nameInput.value = '';
- emailInput.value = '';
- messageInput.value = '';
- rating.checked = false;
-
- showModal('Thank you for your feedback!', 'submit feedback');
-
- return false;
-}
+
+ const formData = new FormData();
+ formData.append("Name", nameInput.value);
+ formData.append("Email", emailInput.value);
+ formData.append("Message", messageInput.value);
+ formData.append("Rating", rating.value);
+
+ // Send the form data to FastAPI using fetch
+ fetch("http://127.0.0.1:8000/submit_feedback", {
+ method: "POST",
+ body: formData, // Send as form data
+ })
+ .then((response) => response.json()) // Parse JSON response from FastAPI
+ .then((data) => {
+ // Handle the response from the FastAPI backend (success or error)
+ if (data.success) {
+ showModal("Thank you for your feedback!", "submit feedback");
+ // Clear form fields after submission
+ nameInput.value = "";
+ emailInput.value = "";
+ messageInput.value = "";
+ const selectedRating = document.querySelector(
+ '[name="rating"]:checked'
+ );
+ if (selectedRating) {
+ selectedRating.checked = false; // Uncheck the selected radio button
+ }
+ } else {
+ alert("Something went wrong, please try again.");
+ }
+ })
+ .catch((error) => {
+ console.error("Error:", error);
+ alert("An error occurred. Please try again.");
+ });
+
+ return false;
+}
function checkFeedbackLength(input) {
- if(input.value.length < 10) {
- document.getElementById('feedbackError').style.opacity = '100%';
- return false;
+ if (input.value.length < 10) {
+ document.getElementById("feedbackError").style.opacity = "100%";
+ return false;
} else {
- document.getElementById('feedbackError').style.opacity = '0%';
- return true;
+ document.getElementById("feedbackError").style.opacity = "0%";
+ return true;
}
}
-windowFunctions.push(checkFeedbackLength);
-
-// EMAIL VALIDATING FUNCTION
+window.checkFeedbackLength = checkFeedbackLength;
+window.validateForm = validateForm;
+
+// EMAIL VALIDATING FUNCTION
function isValidEmail(email) {
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
- return emailRegex.test(email);
+ return emailRegex.test(email);
}
// Display the current year in the copyright section
function displayCopyright() {
const year = new Date().getFullYear();
- if( document.getElementById("copyright").innerText = year) {
+ if ((document.getElementById("copyright").innerText = year)) {
document.getElementById("copyright").innerText = year;
}
}
-ScrollReveal().reveal('.reveal', {
- distance: '150px',
+ScrollReveal().reveal(".reveal", {
+ distance: "150px",
duration: 600,
- easing: 'ease-in-out',
- origin: 'bottom',
+ easing: "ease-in-out",
+ origin: "bottom",
interval: 100, // Delay between revealing multiple elements
});
windowFunctions.push(ScrollReveal);
-
-export {windowFunctions};
\ No newline at end of file
+export { windowFunctions };
diff --git a/website/styles/reviews.css b/website/styles/reviews.css
index e5206f16..736af63e 100644
--- a/website/styles/reviews.css
+++ b/website/styles/reviews.css
@@ -1,188 +1,194 @@
/* Basic resets */
* {
- margin: 0;
- padding: 0;
- box-sizing: border-box;
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
}
body {
- font-family: 'Arial', sans-serif;
- background-color: #000000;
- color: #ffffff;
+ font-family: "Arial", sans-serif;
+ background-color: #000000;
+ color: #ffffff;
}
.reviewContainer {
- text-align: center;
- margin-top: 90px;
+ text-align: center;
+ margin-top: 90px;
}
.reviewHeading {
- color: #ffffff;
- font-size: 30px;
- font-weight: 600;
- margin-bottom: 20px;
+ color: #ffffff;
+ font-size: 30px;
+ font-weight: 600;
+ margin-bottom: 20px;
}
#average-rating {
- padding: 20px;
- text-align: center;
- font-size: 30px;
- margin-bottom: 20px;
- width: 90vw;
- margin-left: 5vw;
- border: 2px solid #dddddd35;
- border-radius: 10px;
+ padding: 20px;
+ text-align: center;
+ font-size: 30px;
+ margin-bottom: 20px;
+ width: 90vw;
+ margin-left: 5vw;
+ border: 2px solid #dddddd35;
+ border-radius: 10px;
}
.average-rating-text {
- font-size: 22px;
+ font-size: 22px;
}
.average-star-rating {
- color: gold;
+ color: gold;
}
.filled {
- color: gold;
- text-shadow: 0 0 10px gold;
+ color: gold;
+ text-shadow: 0 0 10px gold;
}
.half {
- background: linear-gradient(to right, gold, gold, black, black, black);
- background-clip: text;
- -webkit-text-fill-color: transparent;
- text-shadow: -3px 0 10px gold;
+ background: linear-gradient(to right, gold, gold, black, black, black);
+ background-clip: text;
+ -webkit-text-fill-color: transparent;
+ text-shadow: -3px 0 10px gold;
}
.empty {
- margin-left: -25px;
+ margin-left: -25px;
}
/* Review Container */
.reviews-container {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
- gap: 20px;
- padding-bottom: 70px;
- width: 90vw;
- margin-left: 5vw;
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
+ gap: 20px;
+ padding-bottom: 70px;
+ width: 90vw;
+ margin-left: 5vw;
}
.review {
- display: flex;
- flex-direction: column;
- justify-content: space-between;
- position: relative;
- background-color: #50505032;
- border: 1px solid rgba(202, 202, 202, 0.178);
- padding: 15px;
- border-radius: 8px;
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
- transition-duration: 0.3s;
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ position: relative;
+ background-color: #50505032;
+ border: 1px solid rgba(202, 202, 202, 0.178);
+ padding: 15px;
+ border-radius: 8px;
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+ transition-duration: 0.3s;
}
.review-header {
- display: flex;
- align-items: center;
- margin-bottom: 15px;
+ display: flex;
+ align-items: center;
+ margin-bottom: 15px;
}
.review-header h3 {
- font-size: 1.3em;
- color: #cbcbcb;
- border-bottom: 1px solid rgba(255, 255, 255, 0.145);
- width: 100%;
- text-align: left;
- padding-bottom: 5px;
+ font-size: 1.3em;
+ color: #cbcbcb;
+ border-bottom: 1px solid rgba(255, 255, 255, 0.145);
+ width: 100%;
+ text-align: left;
+ padding-bottom: 5px;
}
.review-content {
- position: relative;
- color: #ffffff;
- font-size: 1em;
- text-align: left;
- line-height: 1.6;
- display: flex;
- flex-direction: column;
- height: 100%;
+ position: relative;
+ color: #ffffff;
+ font-size: 1em;
+ text-align: left;
+ line-height: 1.6;
+ display: flex;
+ flex-direction: column;
+ height: 100%;
}
.review-date {
- float: left;
- font-size: 12px;
- color: #888;
- font-style: italic;
+ float: left;
+ font-size: 12px;
+ color: #888;
+ font-style: italic;
}
.review-footer {
- position: relative;
- /* Keep it within the parent review div */
- height: 30px;
- /* Adjust as needed */
- display: flex;
- align-items: flex-end;
- /* Push the date to the bottom */
- justify-content: space-between;
- /* Align the date to the left */
- text-align: right;
+ position: relative;
+ /* Keep it within the parent review div */
+ height: 30px;
+ /* Adjust as needed */
+ display: flex;
+ align-items: flex-end;
+ /* Push the date to the bottom */
+ justify-content: space-between;
+ /* Align the date to the left */
+ text-align: right;
}
.star-rating {
- background: linear-gradient(to right, #ff0000, #fcc100);
- background-clip: text;
- -webkit-text-fill-color: transparent;
- text-shadow: 0 0 10px gold;
+ background: linear-gradient(to right, #ff0000, #fcc100);
+ background-clip: text;
+ -webkit-text-fill-color: transparent;
+ text-shadow: 0 0 10px gold;
}
.star-rating star {
- margin-right: 5px;
- font-size: 1.5rem;
+ margin-right: 5px;
+ font-size: 1.5rem;
}
.goBack {
- cursor: pointer;
- position: fixed;
- bottom: 20px;
- left: 20px;
- padding: 10px;
- background-color: #d0d0d032;
- backdrop-filter: blur(7px);
- color: rgb(105, 105, 105);
- border: none;
- border-radius: 7px;
- box-shadow: 0 0 5px black;
+ cursor: pointer;
+ position: fixed;
+ bottom: 20px;
+ left: 20px;
+ padding: 10px;
+ background-color: #d0d0d032;
+ backdrop-filter: blur(7px);
+ color: rgb(105, 105, 105);
+ border: none;
+ border-radius: 7px;
+ box-shadow: 0 0 5px black;
}
-
.review:hover::before {
- opacity: 1;
+ opacity: 1;
}
.review::before,
.review::after {
- content: "";
- position: absolute;
- top: 0;
- left: 0;
- height: 100%;
- width: 100%;
- border-radius: inherit;
- z-index: 2;
- opacity: 0;
- transition: opacity 500ms;
+ content: "";
+ position: absolute;
+ top: 0;
+ left: 0;
+ height: 100%;
+ width: 100%;
+ border-radius: inherit;
+ z-index: 2;
+ opacity: 0;
+ transition: opacity 500ms;
}
.review::before {
- background: radial-gradient(500px circle at var(--mouse-x) var(--mouse-y), rgba(255, 255, 255, 0.09), transparent 40%);
- z-index: 3;
+ background: radial-gradient(
+ 500px circle at var(--mouse-x) var(--mouse-y),
+ rgba(255, 255, 255, 0.09),
+ transparent 40%
+ );
+ z-index: 3;
}
.review::after {
- background: radial-gradient(300px circle at var(--mouse-x) var(--mouse-y), rgba(255, 255, 255, 0.3), transparent 40%);
- z-index: 1;
+ background: radial-gradient(
+ 300px circle at var(--mouse-x) var(--mouse-y),
+ rgba(255, 255, 255, 0.3),
+ transparent 40%
+ );
+ z-index: 1;
}
-
-#reviews-container:hover>.card:after {
- opacity: 1;
-}
\ No newline at end of file
+#reviews-container:hover > .card:after {
+ opacity: 1;
+}
diff --git a/website/styles/style.css b/website/styles/style.css
index 1b498dcf..eae29780 100644
--- a/website/styles/style.css
+++ b/website/styles/style.css
@@ -1209,7 +1209,40 @@ input {
padding: 10px;
border: 1px solid rgba(128, 128, 128, 0.352);
}
+/* Infinite scroll */
+#examples, #examples2 {
+ display: flex;
+ flex-wrap: nowrap;
+ overflow: hidden;
+ width: 100%;
+}
+
+.examples img {
+ margin-right: 20px;
+ width: 200px;
+}
+
+#examples:not(:hover) img,#examples2:not(:hover) img{
+ animation: scrollImages 10s linear infinite;
+}
+
+#examples:hover img, #examples2:hover img {
+ animation-play-state: paused;
+}
+
+#examples img:hover, #examples2 img:hover {
+ animation-play-state: paused;
+}
+
+@keyframes scrollImages {
+ 0% {
+ transform: translateX(0);
+ }
+ 100% {
+ transform: translateX(-100%);
+ }
+}
/*===========================RESPONSIVE===================================*/
@media screen and (max-width: 660px) {
.navbarButton {
diff --git a/website/templates/404.html b/website/templates/404.html
new file mode 100644
index 00000000..f53f2ba2
--- /dev/null
+++ b/website/templates/404.html
@@ -0,0 +1,29 @@
+
+
+
+
+
+ Page Not Found :(
+
+
+
+
+
+ 4
4
+
+ Oops! Page not found.
+
+ We couldn't find the page you requested. It might be unavailable at the
+ moment or have a different URL.
+
+ Return to Home
+
+
diff --git a/website/pages/contributor.html b/website/templates/contributor.html
similarity index 75%
rename from website/pages/contributor.html
rename to website/templates/contributor.html
index 3496910d..86153c07 100644
--- a/website/pages/contributor.html
+++ b/website/templates/contributor.html
@@ -14,7 +14,7 @@
-
+
Login
@@ -33,28 +33,28 @@