(feat): Init concept of coming soon landing page
This commit is contained in:
parent
18bcafe29b
commit
f8f8c773cc
9 changed files with 179 additions and 77 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -1 +1,3 @@
|
|||
venv/
|
||||
/subscribers.db
|
||||
/.venv/
|
||||
/.github/
|
||||
|
|
|
|||
17
Dockerfile
17
Dockerfile
|
|
@ -1,18 +1,15 @@
|
|||
# Use an official Python runtime as a parent image
|
||||
FROM python:3.10-slim
|
||||
FROM python:3.11-slim-buster
|
||||
|
||||
# Set the working directory in the container
|
||||
WORKDIR /app
|
||||
WORKDIR /rideaware_landing
|
||||
|
||||
# Copy the requirements and application files
|
||||
COPY requirements.txt requirements.txt
|
||||
COPY . .
|
||||
|
||||
# Install Python dependencies
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
# Expose the port Flask runs on
|
||||
COPY . .
|
||||
|
||||
ENV FLASK_APP=server.py
|
||||
|
||||
EXPOSE 5000
|
||||
|
||||
# Define the command to run the app
|
||||
CMD ["python", "server.py"]
|
||||
CMD [ "python3", "-m", "flask", "run", "--host=0.0.0.0"]
|
||||
|
|
|
|||
24
database.py
Normal file
24
database.py
Normal 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
|
||||
18
server.py
18
server.py
|
|
@ -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__)
|
||||
init_db()
|
||||
|
||||
@app.route("/")
|
||||
def index():
|
||||
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__":
|
||||
app.run(debug=True)
|
||||
|
|
|
|||
77
static/css/styles.css
Normal file
77
static/css/styles.css
Normal 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
24
static/js/countdown.js
Normal 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
18
static/js/main.js
Normal 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.");
|
||||
}
|
||||
});
|
||||
|
|
@ -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 */
|
||||
}
|
||||
|
|
@ -3,22 +3,18 @@
|
|||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>RideAware - Coming Soon</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/styles.css">
|
||||
<title>RideAware Landing Page</title>
|
||||
<link rel="stylesheet" href="/static/css/styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1 class="display-4 fw-bold">RideAware</h1>
|
||||
<p class="lead">Our journey begins soon.</p>
|
||||
<!--<p class="mb-4">Sign up to stay updated!</p>
|
||||
<form action="#" class="d-flex justify-content-center">
|
||||
<input type="email" class="form-control me-2" placeholder="Enter your email" required>
|
||||
<button type="submit" class="btn">Notify Me</button>
|
||||
</form>-->
|
||||
<footer>
|
||||
<p class="text-muted">© 2024 RideAware. All rights reserved.</p>
|
||||
</footer>
|
||||
<h1>Coming Soon!</h1>
|
||||
<p>Be the first to know when we launch. Subscribe below:</p>
|
||||
<div class="subscription">
|
||||
<input id="email-input" type="email" placeholder="Enter your email" required />
|
||||
<button id="notify-button">Notify Me</button>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/static/js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue