Added first draft of channel page
This commit is contained in:
37
client/src/components/BrowseLayout.tsx
Normal file
37
client/src/components/BrowseLayout.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import { ArrowLeftIcon } from "@heroicons/react/24/outline";
|
||||
import Button from "../components/Button";
|
||||
import NavBar from "../components/NavBar";
|
||||
import SideNavChannel from "../components/SideNavChannel";
|
||||
import { Outlet } from "react-router-dom";
|
||||
import streamData from "../placeholder/GetStreams";
|
||||
import { NavLink } from "react-router-dom";
|
||||
|
||||
function BrowseLayout() {
|
||||
return (
|
||||
<div className="font-inter flex flex-col h-screen text-gray-100">
|
||||
<NavBar />
|
||||
<main className="flex-1 flex flex-row overflow-hidden">
|
||||
<div className="bg-neutral-800 w-60 flex flex-col">
|
||||
<div className="flex flex-row justify-between p-2 items-center">
|
||||
<p className="uppercase font-semibold text-sm">Followed channels</p>
|
||||
<Button variant="subtle" className="p-2">
|
||||
<ArrowLeftIcon className="w-4 h-4" />
|
||||
</Button>
|
||||
</div>
|
||||
<ul className="flex-1 overflow-scrollbar">
|
||||
{streamData.data.map((stream) => (
|
||||
<li key={stream.id}>
|
||||
<NavLink to={`/${stream.user_login}`}>
|
||||
<SideNavChannel stream={stream} />
|
||||
</NavLink>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
<Outlet />
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default BrowseLayout;
|
||||
34
client/src/components/Button.tsx
Normal file
34
client/src/components/Button.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
import { FC } from "react";
|
||||
import clsx from "clsx";
|
||||
|
||||
type ButtonVariants = "filled" | "subtle";
|
||||
|
||||
interface ButtonProps extends React.ComponentPropsWithoutRef<"button"> {
|
||||
variant?: ButtonVariants;
|
||||
}
|
||||
|
||||
const getStyling = (variant?: ButtonVariants) => {
|
||||
switch (variant) {
|
||||
case "filled":
|
||||
return "bg-neutral-700";
|
||||
case "subtle":
|
||||
return "hover:bg-neutral-500";
|
||||
default:
|
||||
return "bg-neutral-700";
|
||||
}
|
||||
};
|
||||
|
||||
const Button: FC<ButtonProps> = ({
|
||||
className,
|
||||
variant,
|
||||
...rest
|
||||
}: ButtonProps) => {
|
||||
return (
|
||||
<button
|
||||
className={clsx("rounded-md", getStyling(variant), className)}
|
||||
{...rest}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default Button;
|
||||
9
client/src/components/ChatBadge.tsx
Normal file
9
client/src/components/ChatBadge.tsx
Normal file
@@ -0,0 +1,9 @@
|
||||
import { FC } from "react";
|
||||
|
||||
const ChatBadge: FC = () => {
|
||||
return (
|
||||
<div className="w-5 h-5 rounded-sm bg-pink-300 inline-block align-middle" />
|
||||
);
|
||||
};
|
||||
|
||||
export default ChatBadge;
|
||||
23
client/src/components/ChatMessage.tsx
Normal file
23
client/src/components/ChatMessage.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
import { FC } from "react";
|
||||
import ChatBadge from "./ChatBadge";
|
||||
|
||||
const ChatMessage: FC = () => {
|
||||
return (
|
||||
<p className="mx-2 p-2 hover:bg-neutral-700 text-sm rounded-md">
|
||||
<div className="space-x-1 inline">
|
||||
<ChatBadge />
|
||||
<ChatBadge />
|
||||
<span className="align-middle">Username</span>
|
||||
</div>
|
||||
<span className="align-middle">: </span>
|
||||
<span className="break-all align-middle">
|
||||
<img
|
||||
src="https://cdn.7tv.app/emote/60afbe0599923bbe7fe9bae1/2x"
|
||||
className="inline w-7 h-7"
|
||||
/>
|
||||
</span>
|
||||
</p>
|
||||
);
|
||||
};
|
||||
|
||||
export default ChatMessage;
|
||||
17
client/src/components/Input.tsx
Normal file
17
client/src/components/Input.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import clsx from "clsx";
|
||||
|
||||
interface InputProps extends React.ComponentPropsWithoutRef<"input"> {}
|
||||
|
||||
const Input = ({ className, ...rest }: InputProps) => {
|
||||
return (
|
||||
<input
|
||||
className={clsx(
|
||||
"bg-zinc-700 rounded-md box-border focus:outline outline-violet-400 text-sm",
|
||||
className
|
||||
)}
|
||||
{...rest}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default Input;
|
||||
36
client/src/components/NavBar.tsx
Normal file
36
client/src/components/NavBar.tsx
Normal file
@@ -0,0 +1,36 @@
|
||||
import { TvIcon } from "@heroicons/react/24/outline";
|
||||
import { FC } from "react";
|
||||
import Input from "./Input";
|
||||
|
||||
const NavBar: FC = () => {
|
||||
return (
|
||||
<nav className="bg-zinc-800 w-screen font-semibold">
|
||||
<div className="flex flex-row justify-between items-center mx-2">
|
||||
<div className="basis-1/4">
|
||||
<ul className="flex flex-row space-x-3 items-center">
|
||||
<li>
|
||||
<TvIcon className="w-6 h-6" />
|
||||
</li>
|
||||
<li>Following</li>
|
||||
<li>Browse</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="basis-2/4">
|
||||
<div className="flex flex-row space-x-3 items-center justify-center">
|
||||
<Input className=" w-72 my-2 p-2" placeholder="Search" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="basis-1/4">
|
||||
<ul className="justify-end flex flex-row space-x-3 items-center">
|
||||
<li>Hello</li>
|
||||
<li>
|
||||
<div className="w-8 h-8 rounded-full bg-yellow-300" />
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
);
|
||||
};
|
||||
|
||||
export default NavBar;
|
||||
33
client/src/components/SideNavChannel.tsx
Normal file
33
client/src/components/SideNavChannel.tsx
Normal file
@@ -0,0 +1,33 @@
|
||||
import { FC } from "react";
|
||||
import { numFormatter } from "../lib/format";
|
||||
import { Stream } from "../types";
|
||||
|
||||
interface SideNavChannelProps {
|
||||
stream: Stream;
|
||||
}
|
||||
|
||||
const SideNavChannel: FC<SideNavChannelProps> = ({
|
||||
stream,
|
||||
}: SideNavChannelProps) => {
|
||||
const imgSrc = stream.thumbnail_url
|
||||
.replace("{width}", "150")
|
||||
.replace("{height}", "150");
|
||||
|
||||
return (
|
||||
<div className="flex flex-row px-3 py-2 text-sm leading-4 space-x-2 hover:bg-neutral-700/40 cursor-pointer">
|
||||
<img className="rounded-full w-8 h-8" src={imgSrc} />
|
||||
<div className="flex flex-col flex-1">
|
||||
<div className="flex flex-row justify-between">
|
||||
<div className="font-bold">{stream.user_name}</div>
|
||||
<div className="space-x-1 flex flex-row items-center">
|
||||
<div className="w-2 h-2 bg-red-600 rounded-full inline-block" />
|
||||
<span>{numFormatter.format(stream.viewer_count)}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-gray-300">{stream.game_name}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SideNavChannel;
|
||||
Reference in New Issue
Block a user