From f8f8c773cc22726754d6cc31afc8c357435e216c Mon Sep 17 00:00:00 2001 From: Blake Ridgway Date: Sun, 5 Jan 2025 21:03:42 -0600 Subject: [PATCH] (feat): Init concept of coming soon landing page --- .gitignore | 4 ++- Dockerfile | 17 ++++------ database.py | 24 +++++++++++++ server.py | 18 +++++++++- static/css/styles.css | 77 ++++++++++++++++++++++++++++++++++++++++++ static/js/countdown.js | 24 +++++++++++++ static/js/main.js | 18 ++++++++++ static/styles.css | 52 ---------------------------- templates/index.html | 22 +++++------- 9 files changed, 179 insertions(+), 77 deletions(-) create mode 100644 database.py create mode 100644 static/css/styles.css create mode 100644 static/js/countdown.js create mode 100644 static/js/main.js delete mode 100644 static/styles.css diff --git a/.gitignore b/.gitignore index eba74f4..3cc2fac 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ -venv/ \ No newline at end of file +/subscribers.db +/.venv/ +/.github/ diff --git a/Dockerfile b/Dockerfile index ec2f6f5..da90ed6 100644 --- a/Dockerfile +++ b/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"] diff --git a/database.py b/database.py new file mode 100644 index 0000000..b62eea4 --- /dev/null +++ b/database.py @@ -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 \ No newline at end of file diff --git a/server.py b/server.py index 1e0627e..6532065 100644 --- a/server.py +++ b/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) diff --git a/static/css/styles.css b/static/css/styles.css new file mode 100644 index 0000000..3206ced --- /dev/null +++ b/static/css/styles.css @@ -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; +} \ No newline at end of file diff --git a/static/js/countdown.js b/static/js/countdown.js new file mode 100644 index 0000000..bf7a2ea --- /dev/null +++ b/static/js/countdown.js @@ -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 = "

We're Live!

"; + 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); diff --git a/static/js/main.js b/static/js/main.js new file mode 100644 index 0000000..33d8a70 --- /dev/null +++ b/static/js/main.js @@ -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."); + } +}); diff --git a/static/styles.css b/static/styles.css deleted file mode 100644 index 6a28601..0000000 --- a/static/styles.css +++ /dev/null @@ -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 */ -} diff --git a/templates/index.html b/templates/index.html index 2fd088d..54311d7 100644 --- a/templates/index.html +++ b/templates/index.html @@ -3,22 +3,18 @@ - RideAware - Coming Soon - - + RideAware Landing Page +
-

RideAware

-

Our journey begins soon.

- -
-

© 2024 RideAware. All rights reserved.

-
+

Coming Soon!

+

Be the first to know when we launch. Subscribe below:

+
+ + +
+