FIX: Navigation from ListItems;

REFACTOR: Format all files;
This commit is contained in:
Chris-1010
2025-02-23 22:57:00 +00:00
parent 5c81f58e66
commit a27ee52de1
34 changed files with 387 additions and 255 deletions

View File

@@ -1,9 +1,6 @@
import React, { useState } from "react";
import { ToggleButton } from "../Input/Button";
import {
LogIn as LogInIcon,
User as UserIcon,
} from "lucide-react";
import { LogIn as LogInIcon, User as UserIcon } from "lucide-react";
import LoginForm from "./LoginForm";
import RegisterForm from "./RegisterForm";
import ForgotPasswordForm from "./ForgotPasswordForm";
@@ -93,7 +90,10 @@ const AuthModal: React.FC<AuthModalProps> = ({ onClose }) => {
>
</button>
<div id="login-methods" className="w-full flex flex-row items-center justify-evenly">
<div
id="login-methods"
className="w-full flex flex-row items-center justify-evenly"
>
{authSwitch()}
</div>
</div>
@@ -104,4 +104,4 @@ const AuthModal: React.FC<AuthModalProps> = ({ onClose }) => {
);
};
export default AuthModal;
export default AuthModal;

View File

@@ -4,6 +4,7 @@ import Button from "../Input/Button";
interface ForgotPasswordProps {
email?: string;
general?: string;
}
interface SubmitProps {
@@ -51,7 +52,9 @@ const ForgotPasswordForm: React.FC<SubmitProps> = ({ onSubmit }) => {
if (!response.ok) {
const data = await response.json();
throw new Error(data.message || "An error has occurred while resetting");
throw new Error(
data.message || "An error has occurred while resetting"
);
} else {
confirmPasswordReset();
}
@@ -68,8 +71,10 @@ const ForgotPasswordForm: React.FC<SubmitProps> = ({ onSubmit }) => {
return (
<div className="mb-2">
<div className="flex flex-col items-center p-[2.5rem]">
<h1 className="text-white text-[1.5em] font-[800] md:text-[1.75em] lg:text-[2em]">Forgot Password</h1>
<div className="mt-10 bg-white/10 backdrop-blur-md p-6 rounded-xl shadow-lg w-full max-w-[10em] min-w-[14em] border border-white/10 sm:max-w-[16em] md:max-w-[18em] lg:max-w-[20em]">
<h1 className="text-white text-[1.5em] font-[800] md:text-[1.75em] lg:text-[2em]">
Forgot Password
</h1>
<div className="mt-10 bg-white/10 backdrop-blur-md p-6 rounded-xl shadow-lg w-full max-w-[10em] min-w-[14em] border border-white/10 sm:max-w-[16em] md:max-w-[18em] lg:max-w-[20em]">
<form
onSubmit={handleSubmit}
id="forgot-password-form"
@@ -93,7 +98,9 @@ const ForgotPasswordForm: React.FC<SubmitProps> = ({ onSubmit }) => {
placeholder="Enter your email"
value={email}
onChange={handleEmailChange}
extraClasses={`w-full mb-[1.5em] p-[0.5rem] ${errors.email ? "border-red-500" : ""}`}
extraClasses={`w-full mb-[1.5em] p-[0.5rem] ${
errors.email ? "border-red-500" : ""
}`}
/>
</div>
<Button type="submit">Send Link</Button>

View File

@@ -102,9 +102,10 @@ const LoginForm: React.FC<SubmitProps> = ({ onSubmit, onForgotPassword }) => {
return (
<>
<div className="flex flex-col items-center p-10">
<h1 className="flex flex-col text-white text-[1.5em] font-[800] md:text-[1.75em] lg:text-[2em]">Login</h1>
<h1 className="flex flex-col text-white text-[1.5em] font-[800] md:text-[1.75em] lg:text-[2em]">
Login
</h1>
<div className="mt-10 bg-white/10 backdrop-blur-md p-6 rounded-xl shadow-lg w-full max-w-[10em] min-w-[14em] border border-white/10 sm:max-w-[16em] md:max-w-[18em] lg:max-w-[20em]">
<form
onSubmit={handleSubmit}
id="login-form"

View File

@@ -20,7 +20,9 @@ export default function GoogleLogin() {
alt="Google logo"
className="w-[2em] h-[2em] mr-2"
/>
<span className="flex-grow text-[0.6em] lx:text-[0.75em] 2lg:text-[1em]">Sign in with Google</span>
<span className="flex-grow text-[0.6em] lx:text-[0.75em] 2lg:text-[1em]">
Sign in with Google
</span>
</button>
</div>
</div>

View File

@@ -21,7 +21,7 @@ export const Return: React.FC = () => {
const sessionId = urlParams.get("session_id");
if (sessionId) {
console.log("1")
console.log("1");
fetch(`/api/session-status?session_id=${sessionId}`)
.then((res) => res.json())
.then((data) => {

View File

@@ -23,8 +23,7 @@ const Button: React.FC<ButtonProps> = ({
);
};
interface EditButtonProps extends ButtonProps {
}
interface EditButtonProps extends ButtonProps {}
export const EditButton: React.FC<EditButtonProps> = ({
children = "",
@@ -39,7 +38,7 @@ export const EditButton: React.FC<EditButtonProps> = ({
{children}
</button>
);
};
};
interface ToggleButtonProps extends ButtonProps {
toggled?: boolean;

View File

@@ -11,28 +11,26 @@ const Input: React.FC<InputProps> = ({
placeholder = "",
value = "",
extraClasses = "",
onChange = () => { },
onKeyDown = () => { },
onChange = () => {},
onKeyDown = () => {},
children,
...props // all other HTML input props
}) => {
return (
<>
<div className="flex flex-col items-center">
<input
name={name}
type={type}
placeholder={placeholder}
value={value}
onChange={onChange}
onKeyDown={onKeyDown}
{...props}
className={`${extraClasses} relative p-2 rounded-[1rem] w-[20vw] focus:w-[22vw] bg-black/40 border border-gray-300 focus:border-purple-500 focus:outline-purple-500 text-center text-white text-xl transition-all`}
/>
</div>
<div className="flex flex-col items-center">
<input
name={name}
type={type}
placeholder={placeholder}
value={value}
onChange={onChange}
onKeyDown={onKeyDown}
{...props}
className={`${extraClasses} relative p-2 rounded-[1rem] w-[20vw] focus:w-[22vw] bg-black/40 border border-gray-300 focus:border-purple-500 focus:outline-purple-500 text-center text-white text-xl transition-all`}
/>
</div>
</>
);
};

View File

@@ -9,22 +9,27 @@ interface DynamicPageContentProps {
style?: React.CSSProperties;
}
const DynamicPageContent: React.FC<DynamicPageContentProps> = ({
children,
const DynamicPageContent: React.FC<DynamicPageContentProps> = ({
children,
navbarVariant = "default",
className = "",
style
style,
}) => {
const { showSideBar } = useSidebar();
return (
<div className={className} style={style}>
<Navbar variant={navbarVariant} />
<div id="content" className={`${showSideBar ? "w-[85vw] translate-x-[15vw]" : "w-[100vw]"} transition-all duration-[500ms] ease-in-out`}>
<div
id="content"
className={`${
showSideBar ? "w-[85vw] translate-x-[15vw]" : "w-[100vw]"
} transition-all duration-[500ms] ease-in-out`}
>
{children}
</div>
</div>
);
};
export default DynamicPageContent;
export default DynamicPageContent;

View File

@@ -65,7 +65,9 @@ const ListItem: React.FC<ListItemProps> = ({
)}
</div>
<div className="p-3">
<h3 className="font-semibold text-lg text-center truncate max-w-full">{title}</h3>
<h3 className="font-semibold text-lg text-center truncate max-w-full">
{title}
</h3>
{type === "stream" && <p className="font-bold">{username}</p>}
{type === "stream" && (
<p className="text-sm text-gray-300">{streamCategory}</p>

View File

@@ -1,11 +1,16 @@
import React, { forwardRef, useImperativeHandle, useRef, useState } from "react";
import {
ArrowLeft as ArrowLeftIcon,
ArrowRight as ArrowRightIcon,
} from "lucide-react";
import React, {
forwardRef,
useImperativeHandle,
useRef,
useState,
} from "react";
import { useNavigate } from "react-router-dom";
import "../../assets/styles/listRow.css";
import ListItem, { ListItemProps } from "./ListItem";
import { useNavigate } from "react-router-dom";
interface ListRowProps {
variant?: "default" | "search";
@@ -14,7 +19,7 @@ interface ListRowProps {
description?: string;
items: ListItemProps[];
wrap?: boolean;
onClick: (itemName: string) => void;
onItemClick: (itemName: string) => void;
titleClickable?: boolean;
extraClasses?: string;
itemExtraClasses?: string;
@@ -22,8 +27,27 @@ interface ListRowProps {
children?: React.ReactNode;
}
const ListRow = forwardRef<{ addMoreItems: (newItems: ListItemProps[]) => void }, ListRowProps>(
({ variant, type, title = "", description = "", items, wrap, onClick, titleClickable, extraClasses = "", itemExtraClasses = "", amountForScroll, children }, ref) => {
const ListRow = forwardRef<
{ addMoreItems: (newItems: ListItemProps[]) => void },
ListRowProps
>(
(
{
variant = "default",
type,
title = "",
description = "",
items,
onItemClick,
titleClickable = false,
wrap = false,
extraClasses = "",
itemExtraClasses = "",
amountForScroll = 4,
children,
},
ref
) => {
const [currentItems, setCurrentItems] = useState(items);
const slider = useRef<HTMLDivElement>(null);
const scrollAmount = window.innerWidth * 0.3;
@@ -79,7 +103,9 @@ const ListRow = forwardRef<{ addMoreItems: (newItems: ListItemProps[]) => void }
>
<h2
className={`${
titleClickable ? "cursor-pointer hover:underline" : "cursor-default"
titleClickable
? "cursor-pointer hover:underline"
: "cursor-default"
} text-2xl font-bold`}
onClick={titleClickable ? () => handleTitleClick(type) : undefined}
>
@@ -90,7 +116,7 @@ const ListRow = forwardRef<{ addMoreItems: (newItems: ListItemProps[]) => void }
{/* List Items */}
<div className="relative overflow-hidden flex flex-grow items-center z-0">
{!wrap && currentItems.length > (amountForScroll || 0) && (
{!wrap && currentItems.length > amountForScroll && (
<>
<ArrowLeftIcon
onClick={slideLeft}
@@ -126,10 +152,10 @@ const ListRow = forwardRef<{ addMoreItems: (newItems: ListItemProps[]) => void }
onItemClick={() =>
(item.type === "stream" || item.type === "user") &&
item.username
? onClick?.(item.username)
: onClick?.(item.title)
? onItemClick?.(item.username)
: onItemClick?.(item.title)
}
extraClasses={`${itemExtraClasses} min-w-[20vw] max-w-[20vw]`}
extraClasses={`${itemExtraClasses} w-[20vw]`}
/>
))}
</div>
@@ -140,4 +166,4 @@ const ListRow = forwardRef<{ addMoreItems: (newItems: ListItemProps[]) => void }
}
);
export default ListRow;
export default ListRow;

View File

@@ -145,12 +145,12 @@ const Navbar: React.FC<NavbarProps> = ({ variant = "default" }) => {
<SearchBar />
{/* Stream Button */}
{isLoggedIn && !window.location.pathname.includes('go-live') && (
{isLoggedIn && !window.location.pathname.includes("go-live") && (
<Button
extraClasses={`${
variant === "home" ? "absolute top-[2vh] right-[10vw]" : ""
} flex flex-row items-center`}
onClick={() => window.location.href = "/go-live"}
onClick={() => (window.location.href = "/go-live")}
>
<LiveIcon className="h-15 w-15 mr-2" />
Go Live

View File

@@ -85,22 +85,30 @@ const Sidebar: React.FC<SideBarProps> = ({ extraClasses }) => {
className="font-black text-[1.4rem] hover:underline"
onClick={() => navigate(`/user/${username}`)}
>
<div className="text-[var(--sideBar-profile-text)]">
{username}
</div>
<div className="text-[var(--sideBar-profile-text)]">{username}</div>
</button>
</div>
</div>
<div id="following" className="flex flex-col flex-grow justify-evenly gap-4 p-[1rem]">
<div className="bg-[var(--follow-bg)] rounded-[1em] hover:scale-105 transition-all ease-in-out duration-300"
onMouseEnter={(e) => e.currentTarget.style.boxShadow = "var(--follow-shadow)"}
onMouseLeave={(e) => e.currentTarget.style.boxShadow = "none"}
<div
id="following"
className="flex flex-col flex-grow justify-evenly gap-4 p-[1rem]"
>
<div
className="bg-[var(--follow-bg)] rounded-[1em] hover:scale-105 transition-all ease-in-out duration-300"
onMouseEnter={(e) =>
(e.currentTarget.style.boxShadow = "var(--follow-shadow)")
}
onMouseLeave={(e) => (e.currentTarget.style.boxShadow = "none")}
>
<h1 className="text-[var(--follow-text)] font-bold text-2xl p-[0.75rem] cursor-default">Following</h1>
<h1 className="text-[var(--follow-text)] font-bold text-2xl p-[0.75rem] cursor-default">
Following
</h1>
</div>
<div id="streamers-followed" className="flex-grow">
<h2 className="border-b-4 border-t-4 text-2xl cursor-default">Streamers</h2>
<h2 className="border-b-4 border-t-4 text-2xl cursor-default">
Streamers
</h2>
<ul className="mt-2 space-y-2">
{followedStreamers.map((streamer) => (
<li
@@ -115,7 +123,9 @@ const Sidebar: React.FC<SideBarProps> = ({ extraClasses }) => {
</div>
<div id="categories-followed" className="flex-grow">
<h2 className="border-b-4 border-t-4 text-[1.5rem] cursor-default">Categories</h2>
<h2 className="border-b-4 border-t-4 text-[1.5rem] cursor-default">
Categories
</h2>
<ul className="mt-2 space-y-2">
{followedCategories.map((category) => (
<li

View File

@@ -2,7 +2,7 @@ import React from "react";
import ThemeSetting from "./ThemeSetting";
import { useTheme } from "../../context/ThemeContext";
import { useQuickSettings } from "../../context/QuickSettingsContext";
import Screenshot from "../Functionality/Screenshot"
import Screenshot from "../Functionality/Screenshot";
import BrightnessControl from "../Functionality/BrightnessControl";
const QuickSettings: React.FC = () => {
@@ -11,19 +11,24 @@ const QuickSettings: React.FC = () => {
return (
<div
className={`fixed top-0 right-0 w-[20vw] h-screen p-4 flex flex-col items-center overflow-y-hidden overflow-x-hidden ${showQuickSettings ? "opacity-100 z-[90]" : "opacity-0 z-[-1]"
} transition-all duration-300 ease-in-out pt-0 bg-[var(--quickBar-bg)] text-[var(--quickBar-text)]`}
className={`fixed top-0 right-0 w-[20vw] h-screen p-4 flex flex-col items-center overflow-y-hidden overflow-x-hidden ${
showQuickSettings ? "opacity-100 z-[90]" : "opacity-0 z-[-1]"
} transition-all duration-300 ease-in-out pt-0 bg-[var(--quickBar-bg)] text-[var(--quickBar-text)]`}
>
<div className="w-[20vw] p-[1em] flex flex-col items-center bg-[var(--quickBar-title-bg)] text-[var(--quickBar-title)]
border-b-[0.25em] border-[var(--quickBar-border)] ">
<div
className="w-[20vw] p-[1em] flex flex-col items-center bg-[var(--quickBar-title-bg)] text-[var(--quickBar-title)]
border-b-[0.25em] border-[var(--quickBar-border)] "
>
<h1 className="text-[2rem] font-black">Quick Settings</h1>
</div>
<div id="quick-settings-menu" className="flex flex-col flex-grow my-8 gap-4">
<div
id="quick-settings-menu"
className="flex flex-col flex-grow my-8 gap-4"
>
<ThemeSetting />
</div>
<Screenshot />
<BrightnessControl />
<Screenshot />
<BrightnessControl />
</div>
);
};

View File

@@ -140,12 +140,13 @@ const ChatPanel: React.FC<ChatPanelProps> = ({
>
{/* User avatar with image */}
<div
className={`w-2em h-2em rounded-full overflow-hidden flex-shrink-0 ${msg.chatter_username === username ? "" : "cursor-pointer"
}`}
className={`w-2em h-2em rounded-full overflow-hidden flex-shrink-0 ${
msg.chatter_username === username ? "" : "cursor-pointer"
}`}
onClick={() =>
msg.chatter_username === username
? null
: window.location.href = `/user/${msg.chatter_username}`
: (window.location.href = `/user/${msg.chatter_username}`)
}
>
<img
@@ -160,28 +161,33 @@ const ChatPanel: React.FC<ChatPanelProps> = ({
<div className="flex items-center space-x-0.5em">
{/* Username */}
<span
className={`font-bold text-[1em] ${msg.chatter_username === username
className={`font-bold text-[1em] ${
msg.chatter_username === username
? "text-purple-600"
: "text-green-400 cursor-pointer"
}`}
}`}
onClick={() =>
msg.chatter_username === username
? null
: window.location.href = `/user/${msg.chatter_username}`
: (window.location.href = `/user/${msg.chatter_username}`)
}
>
{msg.chatter_username}
</span>
</div>
{/* Message content */}
<div className="message w-full text-[0.9em] mt-0.5em flex flex-col overflow-hidden" >
<div className="message w-full text-[0.9em] mt-0.5em flex flex-col overflow-hidden">
{msg.message}
</div>
</div>
{/* Time sent */}
<div className="text-gray-500 text-[0.8em] absolute top-0 right-0 p-2">
{new Date(msg.time_sent).toLocaleTimeString('en-GB', { hour12: false, hour: '2-digit', minute: '2-digit' })}
{new Date(msg.time_sent).toLocaleTimeString("en-GB", {
hour12: false,
hour: "2-digit",
minute: "2-digit",
})}
</div>
</div>
))}

View File

@@ -44,12 +44,12 @@ const StreamerRoute: React.FC = () => {
if (isLive) {
return <VideoPage streamerId={streamId} />;
}
if (streamerName) {
navigate(`/user/${streamerName}`);
return null;
}
return <div>Streamer not found</div>;
};

View File

@@ -1,5 +1,3 @@
import React from "react";
interface ThumbnailProps {
path: string;
alt?: string;

View File

@@ -32,7 +32,6 @@ const VideoPlayer: React.FC<VideoPlayerProps> = ({
const setupPlayer = async () => {
const streamKey = await fetchStreamKey();
const streamUrl = `/stream/${streamKey}/index.m3u8`;
console.log("Player created with src:", streamUrl);
if (!playerRef.current) {
const videoElement = document.createElement("video");

View File

@@ -4,15 +4,19 @@ import { useBrightness } from "../../context/BrightnessContext";
const BrightnessControl: React.FC = () => {
const { brightness, setBrightness } = useBrightness();
const handleBrightnessChange = (event: React.ChangeEvent<HTMLInputElement>) => {
{/* Set brightness based on the value. Calls BrightnessContext too */}
const handleBrightnessChange = (
event: React.ChangeEvent<HTMLInputElement>
) => {
{
/* Set brightness based on the value. Calls BrightnessContext too */
}
setBrightness(Number(event.target.value));
};
return (
<div className="flex flex-col items-center p-4">
<h2 className="text-lg font-semibold mb-2">Brightness Control</h2>
{/* Changes based on the range of input */}
{/* Changes based on the range of input */}
<input
type="range"
min="0"