aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components.json16
-rw-r--r--src/components/ChannelCard/ChannelCard.tsx94
-rw-r--r--src/components/Divider/Divider.tsx2
-rw-r--r--src/components/channel-card.tsx84
-rw-r--r--src/components/ui/avatar.tsx50
-rw-r--r--src/components/ui/badge.tsx36
-rw-r--r--src/components/ui/card.tsx86
-rw-r--r--src/lib/utils.ts6
-rw-r--r--src/pages/stats/[slug].tsx84
9 files changed, 137 insertions, 321 deletions
diff --git a/components.json b/components.json
deleted file mode 100644
index 2fceff5..0000000
--- a/components.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "$schema": "https://ui.shadcn.com/schema.json",
- "style": "default",
- "rsc": true,
- "tsx": true,
- "tailwind": {
- "config": "tailwind.config.ts",
- "css": "src/app/globals.css",
- "baseColor": "gray",
- "cssVariables": false
- },
- "aliases": {
- "utils": "@/lib/utils",
- "components": "@/components"
- }
-} \ No newline at end of file
diff --git a/src/components/ChannelCard/ChannelCard.tsx b/src/components/ChannelCard/ChannelCard.tsx
new file mode 100644
index 0000000..83471f2
--- /dev/null
+++ b/src/components/ChannelCard/ChannelCard.tsx
@@ -0,0 +1,94 @@
+import React from 'react';
+import Image from 'next/image';
+
+type ChannelCardProps = {
+ channel_id: string;
+ name: string;
+ avatarUrl: string;
+ subscriberCount: number;
+ videoCount: number;
+ viewCount: number;
+ suborg?: string;
+ nextMilestone: string;
+ nextMilestoneDays: string;
+ nextMilestoneDate: string;
+};
+
+const ChannelCard: React.FC<ChannelCardProps> = ({
+ channel_id,
+ name,
+ avatarUrl,
+ subscriberCount,
+ videoCount,
+ viewCount,
+ suborg,
+ nextMilestone,
+ nextMilestoneDays,
+ nextMilestoneDate,
+}) => {
+ return (
+ <div className="max-w-4xl w-full mb-4 mt-4 rounded-xl overflow-hidden shadow-lg bg-gradient-to-r from-gray-800 via-gray-900 to-gray-800 p-4 sm:p-8 hover:shadow-2xl transition-all duration-300">
+ <div className="flex flex-col sm:flex-row items-center mb-6">
+ <Image
+ src={avatarUrl}
+ alt={name}
+ width={80}
+ height={80}
+ className="rounded-full border-4 border-white"
+ />
+ <div className="mt-4 sm:mt-0 sm:ml-6 text-center sm:text-left">
+ <h3 className="text-xl sm:text-2xl font-bold text-white">
+ {name}
+ </h3>
+ {suborg && (
+ <p className="text-sm sm:text-md text-gray-400">
+ {suborg}
+ </p>
+ )}
+ </div>
+ </div>
+ <div className="grid grid-cols-1 sm:grid-cols-3 gap-4 sm:gap-8 text-center mb-6">
+ <div>
+ <p className="text-lg sm:text-xl font-bold text-white">
+ {subscriberCount.toLocaleString()}
+ </p>
+ <p className="text-xs sm:text-sm text-gray-400">
+ Subscribers
+ </p>
+ </div>
+ <div>
+ <p className="text-lg sm:text-xl font-bold text-white">
+ {videoCount.toLocaleString()}
+ </p>
+ <p className="text-xs sm:text-sm text-gray-400">
+ Videos
+ </p>
+ </div>
+ <div>
+ <p className="text-lg sm:text-xl font-bold text-white">
+ {viewCount.toLocaleString()}
+ </p>
+ <p className="text-xs sm:text-sm text-gray-400">
+ Views
+ </p>
+ </div>
+ </div>
+ <div className="bg-gray-700 rounded-lg p-4 mb-6">
+ <p className="text-md sm:text-lg font-semibold text-white">
+ Next Milestone: {Number(nextMilestone).toLocaleString()}
+ </p>
+ <p className="text-xs sm:text-sm text-gray-300">
+ Estimated in {nextMilestoneDays} days ({nextMilestoneDate})
+ </p>
+ </div>
+ <button
+ onClick={() => console.log(`Navigate to channel ${channel_id}`)}
+ className="w-full bg-red-600 hover:bg-red-700 text-white font-bold py-3 px-6 rounded-lg transition-all duration-200"
+ >
+ View Channel on YouTube
+ </button>
+ </div>
+ );
+};
+
+export default ChannelCard; \ No newline at end of file
diff --git a/src/components/Divider/Divider.tsx b/src/components/Divider/Divider.tsx
index e2ef41b..ef6b30b 100644
--- a/src/components/Divider/Divider.tsx
+++ b/src/components/Divider/Divider.tsx
@@ -4,7 +4,7 @@ interface DividerProps {
const Divider = (props: DividerProps) => {
return (
- <div className="flex flex-row items-center justify-center bg-black h-24 mt-8">
+ <div className="flex flex-row items-center justify-center bg-black h-24 max-w-full px-72">
<div className="px-2 text-white text-4xl font-extrabold">
{props.text}
</div>
diff --git a/src/components/channel-card.tsx b/src/components/channel-card.tsx
deleted file mode 100644
index c19f492..0000000
--- a/src/components/channel-card.tsx
+++ /dev/null
@@ -1,84 +0,0 @@
-import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
-import { Badge } from "@/components/ui/badge";
-import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
-
-interface ChannelCardProps {
- channel_id: string;
- name: string;
- avatarUrl: string;
- subscriberCount: number;
- videoCount: number;
- viewCount: number;
- suborg: string;
- nextMilestone: string;
- nextMilestoneDays: string;
- nextMilestoneDate: string;
-}
-
-export function ChannelCard(props: ChannelCardProps) {
- const {
- channel_id,
- name,
- avatarUrl,
- subscriberCount,
- videoCount,
- viewCount,
- suborg,
- nextMilestone,
- nextMilestoneDays,
- nextMilestoneDate,
- } = props;
- return (
- <Card className="w-[500px] shadow-lg rounded-lg overflow-hidden mt-4 py-4">
- <CardHeader>
- <div className="flex items-center space-x-4 p-4">
- <Avatar>
- <AvatarImage src={avatarUrl} />
- <AvatarFallback>PR</AvatarFallback>
- </Avatar>
- <div>
- <a
- className="hover:underline"
- href={`https://youtube.com/channel/${channel_id}`}
- >
- <CardTitle>{name}</CardTitle>
- </a>
- <Badge variant="secondary">{suborg}</Badge>
- </div>
- </div>
- </CardHeader>
- <CardContent className="px-4 py-2 space-y-4">
- <div className="flex flex-col items-center">
- <span className="text-l text-gray-600">Subscribers</span>
- <span className="font-semibold">
- {Number(subscriberCount).toLocaleString()}
- </span>
- </div>
- <div className="flex flex-col items-center">
- <span className="text-l text-gray-600">Videos</span>
- <span className="font-semibold">{videoCount}</span>
- </div>
- <div className="flex flex-col items-center">
- <span className="text-l text-gray-600">View Count</span>
- <span className="font-semibold">
- {Number(viewCount).toLocaleString()}
- </span>
- </div>
- <div className="flex flex-col items-center">
- <span className="text-l text-gray-600">Next Milestone</span>
- <span className="font-semibold">
- {Number(nextMilestone).toLocaleString()}
- </span>
- <div className="flex justify-center items-center">
- <span className="text-sm text-gray-600 px-2">
- {nextMilestoneDays} days
- </span>
- <span className="text-sm text-gray-600 px-2">
- {nextMilestoneDate}
- </span>
- </div>
- </div>
- </CardContent>
- </Card>
- );
-}
diff --git a/src/components/ui/avatar.tsx b/src/components/ui/avatar.tsx
deleted file mode 100644
index 3c884e8..0000000
--- a/src/components/ui/avatar.tsx
+++ /dev/null
@@ -1,50 +0,0 @@
-"use client";
-
-import * as AvatarPrimitive from "@radix-ui/react-avatar";
-import * as React from "react";
-
-import { cn } from "@/lib/utils";
-
-const Avatar = React.forwardRef<
- React.ElementRef<typeof AvatarPrimitive.Root>,
- React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>
->(({ className, ...props }, ref) => (
- <AvatarPrimitive.Root
- ref={ref}
- className={cn(
- "relative flex h-12 w-12 overflow-hidden rounded-full",
- className,
- )}
- {...props}
- />
-));
-Avatar.displayName = AvatarPrimitive.Root.displayName;
-
-const AvatarImage = React.forwardRef<
- React.ElementRef<typeof AvatarPrimitive.Image>,
- React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>
->(({ className, ...props }, ref) => (
- <AvatarPrimitive.Image
- ref={ref}
- className={cn("aspect-square h-full w-full", className)}
- {...props}
- />
-));
-AvatarImage.displayName = AvatarPrimitive.Image.displayName;
-
-const AvatarFallback = React.forwardRef<
- React.ElementRef<typeof AvatarPrimitive.Fallback>,
- React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback>
->(({ className, ...props }, ref) => (
- <AvatarPrimitive.Fallback
- ref={ref}
- className={cn(
- "flex h-full w-full items-center justify-center rounded-full bg-muted",
- className,
- )}
- {...props}
- />
-));
-AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;
-
-export { Avatar, AvatarImage, AvatarFallback };
diff --git a/src/components/ui/badge.tsx b/src/components/ui/badge.tsx
deleted file mode 100644
index f38976c..0000000
--- a/src/components/ui/badge.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-import { type VariantProps, cva } from "class-variance-authority";
-import type * as React from "react";
-
-import { cn } from "@/lib/utils";
-
-const badgeVariants = cva(
- "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
- {
- variants: {
- variant: {
- default:
- "border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
- secondary:
- "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
- destructive:
- "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
- outline: "text-foreground",
- },
- },
- defaultVariants: {
- variant: "default",
- },
- },
-);
-
-export interface BadgeProps
- extends React.HTMLAttributes<HTMLDivElement>,
- VariantProps<typeof badgeVariants> {}
-
-function Badge({ className, variant, ...props }: BadgeProps) {
- return (
- <div className={cn(badgeVariants({ variant }), className)} {...props} />
- );
-}
-
-export { Badge, badgeVariants };
diff --git a/src/components/ui/card.tsx b/src/components/ui/card.tsx
deleted file mode 100644
index 2681236..0000000
--- a/src/components/ui/card.tsx
+++ /dev/null
@@ -1,86 +0,0 @@
-import * as React from "react";
-
-import { cn } from "@/lib/utils";
-
-const Card = React.forwardRef<
- HTMLDivElement,
- React.HTMLAttributes<HTMLDivElement>
->(({ className, ...props }, ref) => (
- <div
- ref={ref}
- className={cn(
- "rounded-lg border bg-card text-card-foreground shadow-sm",
- className,
- )}
- {...props}
- />
-));
-Card.displayName = "Card";
-
-const CardHeader = React.forwardRef<
- HTMLDivElement,
- React.HTMLAttributes<HTMLDivElement>
->(({ className, ...props }, ref) => (
- <div
- ref={ref}
- className={cn("flex flex-col space-y-1 px-4", className)}
- {...props}
- />
-));
-CardHeader.displayName = "CardHeader";
-
-const CardTitle = React.forwardRef<
- HTMLParagraphElement,
- React.HTMLAttributes<HTMLHeadingElement>
->(({ className, ...props }, ref) => (
- <h3
- ref={ref}
- className={cn(
- "text-2xl font-semibold leading-none tracking-tight",
- className,
- )}
- {...props}
- />
-));
-CardTitle.displayName = "CardTitle";
-
-const CardDescription = React.forwardRef<
- HTMLParagraphElement,
- React.HTMLAttributes<HTMLParagraphElement>
->(({ className, ...props }, ref) => (
- <p
- ref={ref}
- className={cn("text-sm text-muted-foreground", className)}
- {...props}
- />
-));
-CardDescription.displayName = "CardDescription";
-
-const CardContent = React.forwardRef<
- HTMLDivElement,
- React.HTMLAttributes<HTMLDivElement>
->(({ className, ...props }, ref) => (
- <div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
-));
-CardContent.displayName = "CardContent";
-
-const CardFooter = React.forwardRef<
- HTMLDivElement,
- React.HTMLAttributes<HTMLDivElement>
->(({ className, ...props }, ref) => (
- <div
- ref={ref}
- className={cn("flex items-center p-6 pt-0", className)}
- {...props}
- />
-));
-CardFooter.displayName = "CardFooter";
-
-export {
- Card,
- CardHeader,
- CardFooter,
- CardTitle,
- CardDescription,
- CardContent,
-};
diff --git a/src/lib/utils.ts b/src/lib/utils.ts
deleted file mode 100644
index ac680b3..0000000
--- a/src/lib/utils.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import { type ClassValue, clsx } from "clsx";
-import { twMerge } from "tailwind-merge";
-
-export function cn(...inputs: ClassValue[]) {
- return twMerge(clsx(inputs));
-}
diff --git a/src/pages/stats/[slug].tsx b/src/pages/stats/[slug].tsx
index dfd63e4..685d01b 100644
--- a/src/pages/stats/[slug].tsx
+++ b/src/pages/stats/[slug].tsx
@@ -4,7 +4,7 @@ import CompactTable from "@/components/CompactTable/CompactTable";
import DataChart from "@/components/DataChart/DataChart";
import Divider from "@/components/Divider/Divider";
import Footer from "@/components/Footer/Footer";
-import { ChannelCard } from "@/components/channel-card";
+import ChannelCard from "@/components/ChannelCard/ChannelCard"
import Head from "next/head";
import TitleBar from "../../components/TitleBar/TitleBar";
@@ -93,48 +93,48 @@ function Page({
showHomeButton
backgroundColor="black"
/>
- <div className="flex justify-center">
- <div className="flex flex-col items-center">
- <ChannelCard
- channel_id={channelData.channel_id}
- name={channelData.channel_name}
- avatarUrl={channelData.profile_pic}
- subscriberCount={channelData.subscribers}
- videoCount={channelData.video_count}
- viewCount={channelData.view_count}
- suborg={channelData.sub_org}
- nextMilestone={channelData.next_milestone}
- nextMilestoneDays={channelData.days_until_next_milestone}
- nextMilestoneDate={channelData.next_milestone_date}
- />
- </div>
+ <div className="flex justify-center px-12 ">
+ <ChannelCard
+ channel_id={channelData.channel_id}
+ name={channelData.channel_name}
+ avatarUrl={channelData.profile_pic}
+ subscriberCount={channelData.subscribers}
+ videoCount={channelData.video_count}
+ viewCount={channelData.view_count}
+ suborg={channelData.sub_org}
+ nextMilestone={channelData.next_milestone}
+ nextMilestoneDays={channelData.days_until_next_milestone}
+ nextMilestoneDate={channelData.next_milestone_date}
+ />
</div>
- <Divider text="Individual Data" />
- <div className="px-48 mb-10 mt-10">
- <div className="mb-12">
- <DataChart
- overrideBGColor="black"
- overrideBorderColor="black"
- chartData={chartData}
- />
- </div>
- <div className="mb-12">
- <DataChart
- chartData={sevenDayGraphData}
- overrideBGColor="black"
- overrideBorderColor="black"
- graphTitle="7 Day Historical"
- />
- </div>
- <Divider text="Milestones" />
- <div className="mb-12">
- <CompactTable
- tableData={{
- dates: milestoneData.dates,
- milestones: milestoneData.milestones,
- }}
- />
- <p className="mt-2 font-semibold">For intervals which we did not record any data, the closest recorded datapoint is chosen</p>
+ <div className="hidden sm:block">
+ <Divider text="Individual Data" />
+ <div className="px-48 mb-10 mt-10">
+ <div className="mb-12">
+ <DataChart
+ overrideBGColor="black"
+ overrideBorderColor="black"
+ chartData={chartData}
+ />
+ </div>
+ <div className="mb-12">
+ <DataChart
+ chartData={sevenDayGraphData}
+ overrideBGColor="black"
+ overrideBorderColor="black"
+ graphTitle="7 Day Historical"
+ />
+ </div>
+ <Divider text="Milestones" />
+ <div className="mb-12">
+ <CompactTable
+ tableData={{
+ dates: milestoneData.dates,
+ milestones: milestoneData.milestones,
+ }}
+ />
+ <p className="mt-2 font-semibold">For intervals which we did not record any data, the closest recorded datapoint is chosen</p>
+ </div>
</div>
</div>
<Footer />
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage