(feat): Init concept of coming soon landing page

This commit is contained in:
Blake Ridgway 2025-01-05 21:03:42 -06:00
parent 18bcafe29b
commit f8f8c773cc
9 changed files with 179 additions and 77 deletions

4
.gitignore vendored
View file

@ -1 +1,3 @@
venv/ /subscribers.db
/.venv/
/.github/

View file

@ -1,18 +1,15 @@
# Use an official Python runtime as a parent image FROM python:3.11-slim-buster
FROM python:3.10-slim
# Set the working directory in the container WORKDIR /rideaware_landing
WORKDIR /app
# Copy the requirements and application files
COPY requirements.txt requirements.txt COPY requirements.txt requirements.txt
COPY . .
# Install Python dependencies
RUN pip install --no-cache-dir -r requirements.txt RUN pip install --no-cache-dir -r requirements.txt
# Expose the port Flask runs on COPY . .
ENV FLASK_APP=server.py
EXPOSE 5000 EXPOSE 5000
# Define the command to run the app CMD [ "python3", "-m", "flask", "run", "--host=0.0.0.0"]
CMD ["python", "server.py"]

24
database.py Normal file
View file

@ -0,0 +1,24 @@
import sqlite3
def init_db():
conn = sqlite3.connect('subscribers.db')
cursor = conn.cursor()
cursor.execute("""
CREATE TABLE IF NOT EXISTS subscribers (
id INTEGER PRIMARY KEY AUTOINCREMENT,
email TEXT UNIQUE NOT NULL
)
""")
conn.commit()
conn.close()
def add_email(email):
try:
conn = sqlite3.connect('subscribers.db')
cursor = conn.cursor()
cursor.execute("INSERT INTO subscribers (email) VALUES (?)", (email,))
conn.commit()
conn.close()
return True
except sqlite3.IntegrityError:
return False

View file

@ -1,10 +1,26 @@
from flask import Flask, render_template # noinspection PyPackageRequirements
from flask import Flask, render_template, request, jsonify
from database import init_db, add_email
app = Flask(__name__) app = Flask(__name__)
init_db()
@app.route("/") @app.route("/")
def index(): def index():
return render_template("index.html") return render_template("index.html")
@app.route("/subscribe", methods=["POST"])
def subscribe():
data = request.get_json()
email = data.get('email')
if not email:
return jsonify({"error": "No email provided"}), 400
if add_email(email):
return jsonify({"message": "Email has been added"}), 201
else:
return jsonify({"error": "Email already exists"}), 400
if __name__ == "__main__": if __name__ == "__main__":
app.run(debug=True) app.run(debug=True)

77
static/css/styles.css Normal file
View file

@ -0,0 +1,77 @@
body {
margin: 0;
padding: 0;
font-family: Arial, sans-serif;
background: linear-gradient(135deg, #1e90ff, #00bfff);
color: #fff;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
.coming-soon {
text-align: center;
max-width: 600px;
padding: 20px;
}
.logo img {
width: 150px;
margin-bottom: 20px;
}
h1 {
font-size: 2.5rem;
margin: 10px 0;
}
p {
font-size: 1.2rem;
margin: 10px 0 20px;
}
.countdown {
display: flex;
justify-content: space-around;
margin: 20px 0;
}
.countdown div {
text-align: center;
}
.countdown span {
display: block;
font-size: 2rem;
font-weight: bold;
}
.subscription {
margin-top: 20px;
}
.subscription input {
padding: 10px;
font-size: 1rem;
width: calc(100% - 110px);
border: none;
border-radius: 10px;
outline: none;
}
.subscription button {
padding: 10px 20px;
font-size: 1rem;
background: #ff4500;
border: none;
border-radius: 10px;
color: #fff;
cursor: pointer;
outline: none;
margin-top: 10px;
}
.subscription button:hover {
background: #e03e00;
}

24
static/js/countdown.js Normal file
View file

@ -0,0 +1,24 @@
// Countdown timer
const targetDate = new Date("2025-01-31T00:00:00Z"); // Set your launch date
function updateCountdown() {
const now = new Date();
const difference = targetDate - now;
if (difference < 0) {
document.getElementById("countdown").innerHTML = "<p>We're Live!</p>";
return;
}
const days = Math.floor(difference / (1000 * 60 * 60 * 24));
const hours = Math.floor((difference / (1000 * 60 * 60)) % 24);
const minutes = Math.floor((difference / (1000 * 60)) % 60);
const seconds = Math.floor((difference / 1000) % 60);
document.getElementById("days").textContent = days.toString().padStart(2, "0");
document.getElementById("hours").textContent = hours.toString().padStart(2, "0");
document.getElementById("minutes").textContent = minutes.toString().padStart(2, "0");
document.getElementById("seconds").textContent = seconds.toString().padStart(2, "0");
}
setInterval(updateCountdown, 1000);

18
static/js/main.js Normal file
View file

@ -0,0 +1,18 @@
document.getElementById("notify-button").addEventListener("click", async () => {
const emailInput = document.getElementById("email-input");
const email = emailInput.value;
if (email) {
const response = await fetch("/subscribe", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email }),
});
const result = await response.json();
alert(result.message || result.error);
emailInput.value = ""; // Clear input field
} else {
alert("Please enter a valid email.");
}
});

View file

@ -1,52 +0,0 @@
body {
background: linear-gradient(135deg, #2E3A59, #4A6FA5); /* Deep blue and soft gray-blue */
color: white;
font-family: 'Arial', sans-serif;
height: 100vh; /* Ensure the body takes full viewport height */
margin: 0;
display: flex; /* Use flexbox to center the content */
justify-content: center; /* Horizontally center */
align-items: center; /* Vertically center */
}
.container {
text-align: center; /* Center-align the text */
max-width: 600px; /* Limit the width for better readability */
}
.logo {
width: 150px;
height: auto;
margin-bottom: 1rem;
}
h1, .lead {
color: #F0F0F0; /* Softer white for contrast */
}
.form-control {
max-width: 300px;
border: 1px solid #6FA8DC; /* Light blue border */
border-radius: 0.25rem;
}
.btn {
background-color: #4A6FA5; /* Soft blue */
border: none;
color: white;
padding: 0.5rem 1.5rem;
font-size: 1rem;
font-weight: bold;
border-radius: 0.25rem;
transition: background-color 0.3s ease;
}
.btn:hover {
background-color: #3B5998; /* Darker blue on hover */
}
footer {
margin-top: 2rem;
font-size: 0.9rem;
color: #D0D0D0; /* Light gray for footer text */
}

View file

@ -3,22 +3,18 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>RideAware - Coming Soon</title> <title>RideAware Landing Page</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet"> <link rel="stylesheet" href="/static/css/styles.css">
<link rel="stylesheet" href="/static/styles.css">
</head> </head>
<body> <body>
<div class="container"> <div class="container">
<h1 class="display-4 fw-bold">RideAware</h1> <h1>Coming Soon!</h1>
<p class="lead">Our journey begins soon.</p> <p>Be the first to know when we launch. Subscribe below:</p>
<!--<p class="mb-4">Sign up to stay updated!</p> <div class="subscription">
<form action="#" class="d-flex justify-content-center"> <input id="email-input" type="email" placeholder="Enter your email" required />
<input type="email" class="form-control me-2" placeholder="Enter your email" required> <button id="notify-button">Notify Me</button>
<button type="submit" class="btn">Notify Me</button> </div>
</form>-->
<footer>
<p class="text-muted">&copy; 2024 RideAware. All rights reserved.</p>
</footer>
</div> </div>
<script src="/static/js/main.js"></script>
</body> </body>
</html> </html>