Major: Added Authentication Functionality, interfaces with backend;

Added new styles to HomePage & VideoPage;
Added AuthContext to persist logged_in status;
This commit is contained in:
Chris-1010
2025-01-24 15:17:53 +00:00
parent ca2a7e9baf
commit 8ec60b1c41
24 changed files with 831 additions and 204 deletions

View File

@@ -1,18 +1,50 @@
import React from "react";
interface ButtonProps {
title?: string;
type?: "button" | "submit" | "reset";
extraClasses?: string;
children?: React.ReactNode;
onClick?: () => void;
}
const Button: React.FC<ButtonProps> = ({
title = "Submit",
type = "button",
children = "Submit",
extraClasses = "",
onClick,
}) => {
return (
<button
type={type}
className={`${extraClasses} p-2 text-[1.5rem] text-white hover:text-purple-600 bg-black/30 hover:bg-black/80 rounded-md border border-gray-300 hover:border-purple-500 hover:border-b-4 hover:border-l-4 active:border-b-2 active:border-l-2 transition-all`}
onClick={onClick}
>
{children}
</button>
);
};
interface ToggleButtonProps extends ButtonProps {
toggled?: boolean;
}
export const ToggleButton: React.FC<ToggleButtonProps> = ({
children = "Toggle",
extraClasses = "",
onClick,
toggled = false,
}) => {
toggled
? (extraClasses += " cursor-default bg-purple-600")
: (extraClasses +=
" cursor-pointer hover:text-purple-600 hover:bg-black/80 hover:border-purple-500 hover:border-b-4 hover:border-l-4");
return (
<div>
<button className="underline bg-blue-600/30 p-4 rounded-[5rem] transition-all hover:text-[3.2rem]" onClick={onClick}>
{title}
<button
className={`${extraClasses} p-2 text-[1.5rem] text-white bg-black/30 rounded-[1rem] border border-gray-300 transition-all`}
onClick={onClick}
>
{children}
</button>
</div>
);

View File

@@ -0,0 +1,29 @@
import React from "react";
interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
extraClasses?: string;
}
const Input: React.FC<InputProps> = ({
name,
type = "text",
placeholder = "",
value = "",
extraClasses = "",
onChange = () => {},
...props // all other HTML input props
}) => {
return (
<input
name={name}
type={type}
placeholder={placeholder}
value={value}
onChange={onChange}
{...props}
className={`${extraClasses} p-2 rounded-[1rem] w-[20vw] focus:w-[120%] bg-black/40 border border-gray-300 focus:border-purple-500 focus:outline-purple-500 text-center text-white text-xl transition-all`}
/>
);
};
export default Input;

View File

@@ -17,20 +17,20 @@ interface ListRowProps {
title: string;
description: string;
streams: StreamItem[];
onStreamClick?: (streamId: string) => void;
onStreamClick?: (streamerId: string) => void;
}
// Individual stream entry component
const ListEntry: React.FC<ListEntryProps> = ({ stream, onClick }) => {
return (
<div
className="flex flex-col bg-gray-800 rounded-lg overflow-hidden cursor-pointer hover:bg-gray-700 transition-colors"
className="flex flex-col bg-gray-800 rounded-lg overflow-hidden cursor-pointer hover:bg-gray-700 border border-gray-100 hover:border-purple-500 hover:border-b-4 hover:border-l-4 transition-all"
onClick={onClick}
>
<div className="relative w-full pt-[56.25%]">
{stream.thumbnail ? (
<img
src={`images/`+stream.thumbnail}
src={`images/` + stream.thumbnail}
alt={stream.title}
className="absolute top-0 left-0 w-full h-full object-cover"
/>
@@ -55,7 +55,7 @@ const ListRow: React.FC<ListRowProps> = ({
onStreamClick,
}) => {
return (
<div className="flex flex-col space-y-4 py-6">
<div className="flex flex-col space-y-4 py-6 mx-4">
<div className="space-y-1">
<h2 className="text-2xl font-bold">{title}</h2>
<p className="text-gray-400">{description}</p>
@@ -65,7 +65,7 @@ const ListRow: React.FC<ListRowProps> = ({
<ListEntry
key={stream.id}
stream={stream}
onClick={() => onStreamClick?.(stream.id)}
onClick={() => onStreamClick?.(stream.streamer)}
/>
))}
</div>

View File

@@ -1,18 +1,25 @@
import React from "react";
import { Link } from "react-router-dom";
const Logo: React.FC = () => {
const gradient =
"bg-gradient-to-br from-yellow-400 via-red-500 to-indigo-500 text-transparent bg-clip-text group-hover:mx-1 transition-all";
return (
<div className="text-center text-[12vh] font-bold text-orange-500">
<h6 className="text-sm">Go on, have a...</h6>
<div className="flex justify-center items-center space-x-6">
<span>G</span>
<span>A</span>
<span>N</span>
<span>D</span>
<span>E</span>
<span>R</span>
<Link to="/" className="cursor-pointer">
<div className="logo group py-3 text-center text-[12vh] font-bold hover:scale-110 transition-all">
<h6 className="text-sm bg-gradient-to-br from-blue-400 via-green-500 to-indigo-500 font-black text-transparent bg-clip-text">
Go on, have a...
</h6>
<div className="flex w-fit min-w-[30vw] justify-evenly leading-none transition-all">
<span className={gradient}>G</span>
<span className={gradient}>A</span>
<span className={gradient}>N</span>
<span className={gradient}>D</span>
<span className={gradient}>E</span>
<span className={gradient}>R</span>
</div>
</div>
</div>
</Link>
);
};

View File

@@ -1,56 +1,90 @@
import React from "react";
import React, { useState, useEffect } from "react";
import Logo from "./Logo";
import Button from "./Button";
import { Link } from "react-router-dom";
import { Search, User, LogIn } from "lucide-react";
import Sidebar from "./Sidebar";
import { Sidebar as SidebarIcon } from "lucide-react";
import {
Search as SearchIcon,
LogIn as LogInIcon,
LogOut as LogOutIcon,
Settings as SettingsIcon,
} from "lucide-react";
import Input from "./Input";
import AuthModal from "../Auth/AuthModal";
import { useAuth } from "../../context/AuthContext";
interface NavbarProps {
logged_in: boolean;
}
const Navbar: React.FC = () => {
const [showAuthModal, setShowAuthModal] = useState(false);
const { isLoggedIn } = useAuth();
useEffect(() => {
if (showAuthModal) {
document.body.style.overflow = "hidden";
} else {
document.body.style.overflow = "unset";
}
return () => {
document.body.style.overflow = "unset";
};
}, [showAuthModal]);
const handleLogout = () => {
console.log("Logging out...");
fetch("/api/logout")
.then((response) => response.json())
.then((data) => {
console.log(data);
window.location.reload();
});
};
const Navbar: React.FC<NavbarProps> = ({ logged_in }) => {
return (
<div className="flex flex-col justify-around items-center h-[45vh]">
<Logo />
<div className="nav-buttons flex items-center space-x-4">
{logged_in ? (
<div>
<Link
to="/logout"
className="flex items-center text-gray-700 hover:text-purple-600"
>
<Button title="" />
</Link>
</div>
<Button
extraClasses="absolute top-[20px] left-[20px] text-[1rem] flex items-center flex-nowrap"
onClick={() => (isLoggedIn ? handleLogout() : setShowAuthModal(true))}
>
{isLoggedIn ? (
<>
<LogOutIcon className="h-15 w-15 mr-1" />
Logout
</>
) : (
<div>
<Link
to="/login"
className="flex items-center text-gray-700 hover:text-purple-600"
>
<LogIn className="h-5 w-5 mr-1" />
Login
</Link>
<Link
to="/signup"
className="flex items-center text-gray-700 hover:text-purple-600"
>
<User className="h-5 w-5 mr-1" />
Sign Up
</Link>
</div>
<>
<LogInIcon className="h-15 w-15 mr-1" />
Login / Register
</>
)}
<Button title="Quick Settings" />
</div>
</Button>
<div className="search-bar relative">
<input
{isLoggedIn && (
<>
<Button extraClasses="absolute top-[75px] left-[20px]">
<SidebarIcon className="h-15 w-15 mr-1" />
</Button>
<Sidebar />
</>
)}
<Button
extraClasses="absolute top-[20px] right-[20px] text-[1rem] flex items-center flex-nowrap"
onClick={() => console.log("Settings")}
>
<SettingsIcon className="h-15 w-15 mr-1" />
Quick Settings
</Button>
<div className="search-bar flex items-center">
<Input
type="text"
placeholder="Search..."
className="w-64 px-4 py-2 rounded-lg border border-gray-300 focus:outline-none focus:border-purple-500"
extraClasses="pr-[30px] focus:outline-none focus:border-purple-500 focus:w-[30vw]"
/>
<Search className="absolute right-3 top-2.5 h-5 w-5 text-gray-400" />
<SearchIcon className="-translate-x-[28px] top-1/2 h-6 w-6 text-white" />
</div>
{showAuthModal && <AuthModal onClose={() => setShowAuthModal(false)} />}
</div>
);
};

View File

@@ -0,0 +1,7 @@
import React from "react";
const Sidebar: React.FC = () => {
return <div></div>;
};
export default Sidebar;