diff --git a/web_server/Dockerfile b/web_server/Dockerfile index a63ac40..55d38ff 100644 --- a/web_server/Dockerfile +++ b/web_server/Dockerfile @@ -11,7 +11,7 @@ RUN pip install --no-cache-dir -r requirements.txt COPY . . # Set environment variables -ENV FLASK_APP=blueprints.__init__ +ENV FLASK_APP=backend.blueprints.__init__ ENV FLASK_DEBUG=True # Expose Flask's port diff --git a/web_server/backend/blueprints/__init__.py b/web_server/backend/blueprints/__init__.py index 97500d5..2a33ccb 100644 --- a/web_server/backend/blueprints/__init__.py +++ b/web_server/backend/blueprints/__init__.py @@ -4,7 +4,7 @@ from backend.blueprints.utils import logged_in_user from flask_cors import CORS def create_app(): - app = Flask(__name__, template_folder="../ui/templates/", static_folder="../ui/static/") + app = Flask(__name__, static_folder="../ui/static/") app.config["SECRET_KEY"] = "" app.config["SESSION_PERMANENT"] = False app.config["SESSION_TYPE"] = "filesystem" diff --git a/web_server/backend/blueprints/main.py b/web_server/backend/blueprints/main.py index a6305e0..7fbb44a 100644 --- a/web_server/backend/blueprints/main.py +++ b/web_server/backend/blueprints/main.py @@ -3,6 +3,15 @@ from flask import render_template, Blueprint main_bp = Blueprint("app", __name__) +@main_bp.route('/get_loggedin_status') +def get_loggedin_status(): + logged_in = False + """ + Returns whether the user is logged in or not + """ + return {"logged_in": logged_in} + + @main_bp.route('/get_streams') def get_sample_streams(): """ @@ -14,29 +23,37 @@ def get_sample_streams(): "title": "Gaming Stream", "streamer": "Gamer123", "viewers": 1500, - "thumbnail": "assets/images/monkey.png", + "thumbnail": "dance_game.png", }, { "id": 2, "title": "Art Stream", "streamer": "Artist456", "viewers": 800, - "thumbnail": "assets/images/surface.jpeg", + "thumbnail": "surface.jpeg", }, { "id": 3, "title": "Music Stream", "streamer": "Musician789", "viewers": 2000, - "thumbnail": "assets/images/dance_game.png", + "thumbnail": "monkey.png", }, { "id": 4, "title": "Just Chatting", "streamer": "Chatty101", "viewers": 1200, - "thumbnail": "assets/images/elf.webp", + "thumbnail": "elf.webp", }, + { + "id": 5, + "title": "Cooking Stream", + "streamer": "Chef202", + "viewers": 1000, + "thumbnail": "art.jpg", + } ] return streamers +#TODO Route for saving uploaded thumbnails to database, serving these images to the frontend upon request: →→→ @main_bp.route('/images/') \n def serve_image(filename): ←←← \ No newline at end of file diff --git a/web_server/frontend/index.html b/web_server/frontend/index.html index b42ffce..e6ceec8 100644 --- a/web_server/frontend/index.html +++ b/web_server/frontend/index.html @@ -7,7 +7,7 @@ Team Software Project -
+
diff --git a/web_server/frontend/public/images/art.jpg b/web_server/frontend/public/images/art.jpg new file mode 100644 index 0000000..a477bb4 Binary files /dev/null and b/web_server/frontend/public/images/art.jpg differ diff --git a/web_server/frontend/public/images/background-pattern.svg b/web_server/frontend/public/images/background-pattern.svg new file mode 100644 index 0000000..db99d8b --- /dev/null +++ b/web_server/frontend/public/images/background-pattern.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web_server/frontend/public/images/dance_game.png b/web_server/frontend/public/images/dance_game.png new file mode 100644 index 0000000..0f9ac82 Binary files /dev/null and b/web_server/frontend/public/images/dance_game.png differ diff --git a/web_server/frontend/src/assets/images/elf.webp b/web_server/frontend/public/images/elf.webp similarity index 100% rename from web_server/frontend/src/assets/images/elf.webp rename to web_server/frontend/public/images/elf.webp diff --git a/web_server/frontend/public/images/monkey.png b/web_server/frontend/public/images/monkey.png new file mode 100644 index 0000000..2be60e8 Binary files /dev/null and b/web_server/frontend/public/images/monkey.png differ diff --git a/web_server/frontend/src/assets/images/surface.jpeg b/web_server/frontend/public/images/surface.jpeg similarity index 100% rename from web_server/frontend/src/assets/images/surface.jpeg rename to web_server/frontend/public/images/surface.jpeg diff --git a/web_server/frontend/src/assets/images/dance_game.png b/web_server/frontend/src/assets/images/dance_game.png deleted file mode 100644 index cd7aff7..0000000 Binary files a/web_server/frontend/src/assets/images/dance_game.png and /dev/null differ diff --git a/web_server/frontend/src/assets/images/monkey.png b/web_server/frontend/src/assets/images/monkey.png deleted file mode 100644 index 4c75641..0000000 Binary files a/web_server/frontend/src/assets/images/monkey.png and /dev/null differ diff --git a/web_server/frontend/src/components/Layout/Button.tsx b/web_server/frontend/src/components/Layout/Button.tsx new file mode 100644 index 0000000..efa82c7 --- /dev/null +++ b/web_server/frontend/src/components/Layout/Button.tsx @@ -0,0 +1,17 @@ +import React from 'react' + +interface ButtonProps { + title?: string; + alt?: string; + onClick?: () => void; +} + +const Button = ({ title, alt, onClick }: ButtonProps) => { + return ( +
+ +
+ ) +} + +export default Button diff --git a/web_server/frontend/src/components/Layout/ListRow.tsx b/web_server/frontend/src/components/Layout/ListRow.tsx new file mode 100644 index 0000000..2537a64 --- /dev/null +++ b/web_server/frontend/src/components/Layout/ListRow.tsx @@ -0,0 +1,76 @@ +import React from "react"; + +interface StreamItem { + id: number; + title: string; + streamer: string; + viewers: number; + thumbnail?: string; +} + +interface ListEntryProps { + stream: StreamItem; + onClick?: () => void; +} + +interface ListRowProps { + title: string; + description: string; + streams: StreamItem[]; + onStreamClick?: (streamId: string) => void; +} + +// Individual stream entry component +const ListEntry: React.FC = ({ stream, onClick }) => { + return ( +
+
+ {stream.thumbnail ? ( + {stream.title} + ) : ( +
+ )} +
+
+

{stream.title}

+

{stream.streamer}

+

{stream.viewers} viewers

+
+
+ ); +}; + +// Row of stream entries +const ListRow: React.FC = ({ + title, + description, + streams, + onStreamClick, +}) => { + return ( +
+
+

{title}

+

{description}

+
+
+ {streams.map((stream) => ( + onStreamClick?.(stream.id)} + /> + ))} +
+
+ ); +}; + +export default ListRow; diff --git a/web_server/frontend/src/components/Layout/Logo.tsx b/web_server/frontend/src/components/Layout/Logo.tsx new file mode 100644 index 0000000..040b558 --- /dev/null +++ b/web_server/frontend/src/components/Layout/Logo.tsx @@ -0,0 +1,19 @@ +import React from "react"; + +const Logo: React.FC = () => { + return ( +
+
Go on, have a...
+
+ G + A + N + D + E + R +
+
+ ); +}; + +export default Logo; diff --git a/web_server/frontend/src/components/Layout/Navbar.tsx b/web_server/frontend/src/components/Layout/Navbar.tsx new file mode 100644 index 0000000..bf6f2c5 --- /dev/null +++ b/web_server/frontend/src/components/Layout/Navbar.tsx @@ -0,0 +1,58 @@ +import React from "react"; +import Logo from "./Logo"; +import Button from "./Button"; +import { Link } from "react-router-dom"; +import { Search, User, LogIn } from "lucide-react"; + +interface NavbarProps { + logged_in: boolean; +} + +const Navbar: React.FC = ({ logged_in }) => { + return ( +
+ +
+ {logged_in ? ( +
+ +
+ ) : ( +
+ + + Login + + + + Sign Up + +
+ )} +
+ +
+ + +
+
+ ); +}; + +export default Navbar; diff --git a/web_server/frontend/src/components/Stream/Thumbnail.tsx b/web_server/frontend/src/components/Stream/Thumbnail.tsx new file mode 100644 index 0000000..e450c86 --- /dev/null +++ b/web_server/frontend/src/components/Stream/Thumbnail.tsx @@ -0,0 +1,21 @@ +import React from 'react' + +interface ThumbnailProps { + path: string; + alt?: string; +} + +const Thumbnail = ({ path, alt }: ThumbnailProps) => { + return ( +
+ {alt} +
+ ) +} + +export default Thumbnail diff --git a/web_server/frontend/src/pages/HomePage.tsx b/web_server/frontend/src/pages/HomePage.tsx index b99d929..dbc489b 100644 --- a/web_server/frontend/src/pages/HomePage.tsx +++ b/web_server/frontend/src/pages/HomePage.tsx @@ -1,71 +1,57 @@ import React, { useState, useEffect } from "react"; +import Navbar from "../components/Layout/Navbar"; +import ListRow from "../components/Layout/ListRow"; // import { data, Link } from "react-router-dom"; -// import { Search, User, LogIn } from "lucide-react"; + +const handleStreamClick = (streamId: string) => { + // Handle navigation to stream page + console.log(`Navigating to stream ${streamId}`); +}; + +interface StreamItem { + id: number; + title: string; + streamer: string; + viewers: number; + thumbnail?: string; +} const HomePage: React.FC = () => { - const [featuredStreams, setFeaturedStreams] = useState([{}]); + const [featuredStreams, setFeaturedStreams] = useState([]); + const [loggedInStatus, setLoggedInStatus] = useState(false); - //! ↓↓ runs twice when in development mode + // ↓↓ runs twice when in development mode useEffect(() => { - fetch("http://127.0.0.1:5000/get_streams") + fetch("http://127.0.0.1:5000/get_loggedin_status") .then((response) => response.json()) .then((data) => { + setLoggedInStatus(data); + console.log(data); + }); + fetch("http://127.0.0.1:5000/get_streams") + .then((response) => response.json()) + .then((data: StreamItem[]) => { setFeaturedStreams(data); console.log(data); }); }, []); return ( -
- +
+ -
Behold, your next great watch!
- -
- {/* */} -
- -

Live Now

-
- {featuredStreams.map((stream: any) => ( -
- Stream thumbnail -
-
- {stream.streamer} -
-
{stream.title}
-
{stream.viewers} viewers
-
-
- ))} -
- -

Trending Categories

-
-
-
-
-
-
-
+ +
); }; diff --git a/web_server/frontend/tailwind.config.js b/web_server/frontend/tailwind.config.js index 89a305e..559b7bf 100644 --- a/web_server/frontend/tailwind.config.js +++ b/web_server/frontend/tailwind.config.js @@ -5,7 +5,8 @@ export default { "./src/**/*.{js,ts,jsx,tsx}", ], theme: { - extend: {}, + extend: { + }, }, plugins: [], } \ No newline at end of file diff --git a/web_server/requirements.txt b/web_server/requirements.txt index 3b5b9c9..9300d09 100644 --- a/web_server/requirements.txt +++ b/web_server/requirements.txt @@ -7,6 +7,7 @@ colorama==0.4.6 Flask==3.1.0 Flask-Session==0.8.0 Flask-WTF==1.2.2 +Flask_CORS==5.0.0 python-dotenv==1.0.1 idna==3.10 itsdangerous==2.2.0