Skip to content

Commit

Permalink
assortment of UI improvements, add stats to menu
Browse files Browse the repository at this point in the history
  • Loading branch information
sphinxrave committed Jun 13, 2024
1 parent 2fbaa54 commit f4d5527
Show file tree
Hide file tree
Showing 11 changed files with 267 additions and 21 deletions.
1 change: 1 addition & 0 deletions packages/react/src/components/about/ContactList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export function ContactList() {
</a>
</Button>
</div>
<div className="h-4"></div>
{/* <AboutHeading>{t("about.contact.discord")}</AboutHeading>
<Link to="https://discord.gg/A24AbzgvRJ" target="_blank">
<img
Expand Down
5 changes: 1 addition & 4 deletions packages/react/src/components/about/Description.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@ export function AboutDescription(
>,
) {
return (
<p
{...props}
className={cn("mt-2 leading-8 tracking-wide", props.className)}
/>
<p {...props} className={cn("mt-2 indent-4 leading-8", props.className)} />
);
}
9 changes: 8 additions & 1 deletion packages/react/src/components/about/EmailForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,13 @@ const formSchema = z.object({
.string()
.min(1, { message: "Email is required" })
.email({ message: "Email is invalid" }),
message: z.string().min(80, { message: "Message is required" }),
message: z
.string()
.min(1, { message: "Message is required" })
.min(20, {
message: "Message must be at least 20 characters",
})
.max(500, { message: "Message must be less than 500 characters" }),
});

export function AboutFaqEmailForm() {
Expand Down Expand Up @@ -90,6 +96,7 @@ export function AboutFaqEmailForm() {
)}
/>
<Button type="submit" variant="ghost" className="" size="lg">
<div className="i-heroicons:envelope"></div>
{t("about.contactForm.sendButton")}
</Button>
</form>
Expand Down
79 changes: 79 additions & 0 deletions packages/react/src/components/about/Stats.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/**
* v0 by Vercel.
* @see https://v0.dev/t/KfbKQpc7Uhn
* Documentation: https://v0.dev/docs#integrating-generated-code-into-your-nextjs-app
*/
"use client";

import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/shadcn/ui/card";
import { useState, useEffect } from "react";

interface StatBlockProps {
title: string;
amount: number;
change?: number;
duration: number;
timeText?: string; // e.g. "last week"
}

/**
* Renders a statistic component with an animated display of the amount.
*
* @param {StatBlockProps} props - The props for the component.
* @param {string} props.title - The title of the statistic.
* @param {number} props.amount - The initial amount to display.
* @param {number} props.change - The change in the amount.
* @param {number} props.duration - The duration of the animation in milliseconds.
* @param {string} props.timeText - The text to display after the amount.
* @return {JSX.Element} The rendered statistic component.
*/
export default function StatComponent({
title,
amount,
change,
duration,
timeText,
}: StatBlockProps) {
const [displayAmount, setDisplayAmount] = useState(0);

useEffect(() => {
const startTime = performance.now();
const animationLoop = (currentTime: number) => {
const elapsedTime = currentTime - startTime;
const progress = Math.min(elapsedTime / duration, 1);
const currentAmount = Math.floor(progress * amount);
setDisplayAmount(currentAmount);
if (progress < 1) {
requestAnimationFrame(animationLoop);
}
};
requestAnimationFrame(animationLoop);
}, [amount, duration]);

return (
<Card className="">
<CardHeader className="pb-2">
<CardDescription>{title}</CardDescription>
<CardTitle className="text-4xl">
{displayAmount.toLocaleString()}
</CardTitle>
</CardHeader>
<CardContent>
{change && (
<div
className={`text-xs ${displayAmount > 0 ? "text-green-10" : "text-red-10"}`}
>
{change > 0 ? `+${change}` : `${change}`}
{timeText}
</div>
)}
</CardContent>
</Card>
);
}
1 change: 0 additions & 1 deletion packages/react/src/components/player/QueueList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
} from "@/shadcn/ui/collapsible";
import { useMemo, useState } from "react";
import NewPlaylistDialog from "../playlist/NewPlaylistDialog";
import { cn } from "@/lib/utils";
import { WATCH_PAGE_DROPDOWN_BUTTON_STYLE } from "@/shadcn/ui/button.variants";

export function QueueList({ currentId }: { currentId?: string }) {
Expand Down
4 changes: 2 additions & 2 deletions packages/react/src/components/sidebar/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -193,10 +193,10 @@ function SidebarItem({
className={cn(
"w-full justify-start",
className,
{ "text-base-12 font-semibold": isHere },
{ "text-base-12 font-semibold tracking-tight": isHere },
{ "font-base-11 font-light": !isHere },
)}
variant={isHere ? "default" : "ghost"}
variant={isHere ? "primary" : "ghost"}
onClick={isMobile ? onClose : undefined}
>
<Link to={href}>
Expand Down
2 changes: 1 addition & 1 deletion packages/react/src/hooks/useFrame.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { atom } from "jotai";
import { atomWithStorage } from "jotai/utils";

const MobileSizeBreak = 768;
const MobileSizeBreak = 868;
const FooterSizeBreak = 500;

export const sidebarPrefOpenAtom = atomWithStorage(
Expand Down
43 changes: 33 additions & 10 deletions packages/react/src/routes/about/faq.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,20 @@ import {
import { useTranslation } from "react-i18next";
import { Link } from "react-router-dom";

function FaqQuestion({ children }: { children: React.ReactNode }) {
return <h3 className="text-xl font-semibold tracking-tight">{children}</h3>;
}

export function AboutFaq() {
const { t } = useTranslation();

return (
<div>
<Accordion type="multiple">
<AccordionItem value="youtube">
<AccordionTrigger>{t("about.faq.ytchatHeader")}</AccordionTrigger>
<AccordionTrigger>
<FaqQuestion>{t("about.faq.ytchatHeader")}</FaqQuestion>
</AccordionTrigger>
<AccordionContent>
<AboutDescription className="mb-2">
{t("about.faq.ytchatContent")}
Expand All @@ -32,7 +38,9 @@ export function AboutFaq() {
</AccordionContent>
</AccordionItem>
<AccordionItem value="autoplay">
<AccordionTrigger>{t("about.faq.autoplayHeader")}</AccordionTrigger>
<AccordionTrigger>
<FaqQuestion>{t("about.faq.autoplayHeader")}</FaqQuestion>
</AccordionTrigger>
<AccordionContent>
<AboutDescription>
{t("about.faq.autoplayContent")}
Expand All @@ -44,7 +52,9 @@ export function AboutFaq() {
</AccordionContent>
</AccordionItem>
<AccordionItem value="mobile">
<AccordionTrigger>{t("about.faq.mobile.title")}</AccordionTrigger>
<AccordionTrigger>
<FaqQuestion>{t("about.faq.mobile.title")}</FaqQuestion>
</AccordionTrigger>
<AccordionContent>
<AboutDescription>
{t("about.faq.mobile.content.summary")}
Expand All @@ -65,7 +75,7 @@ export function AboutFaq() {
</AccordionItem>
<AccordionItem value="favorite-disappear">
<AccordionTrigger>
{t("about.faq.favorite.disappear.title")}
<FaqQuestion>{t("about.faq.favorite.disappear.title")}</FaqQuestion>
</AccordionTrigger>
<AccordionContent>
<AboutDescription>
Expand All @@ -74,7 +84,9 @@ export function AboutFaq() {
</AccordionContent>
</AccordionItem>
<AccordionItem value="subber">
<AccordionTrigger>{t("about.faq.subber.title")}</AccordionTrigger>
<AccordionTrigger>
<FaqQuestion>{t("about.faq.subber.title")}</FaqQuestion>
</AccordionTrigger>
<AccordionContent>
<AboutDescription>
{t("about.faq.subber.contents.0")}
Expand All @@ -89,31 +101,39 @@ export function AboutFaq() {
</AccordionContent>
</AccordionItem>
<AccordionItem value="video">
<AccordionTrigger>{t("about.faq.videoLinkage")}</AccordionTrigger>
<AccordionTrigger>
<FaqQuestion>{t("about.faq.videoLinkage")}</FaqQuestion>
</AccordionTrigger>
<AccordionContent>
<AboutDescription>
{t("about.faq.videoLinkageContent")}
</AboutDescription>
</AccordionContent>
</AccordionItem>
<AccordionItem value="quit">
<AccordionTrigger>{t("about.faq.quitHolodex")}</AccordionTrigger>
<AccordionTrigger>
<FaqQuestion>{t("about.faq.quitHolodex")}</FaqQuestion>
</AccordionTrigger>
<AccordionContent>
<AboutDescription>
{t("about.faq.quitHolodexContent")}
</AboutDescription>
</AccordionContent>
</AccordionItem>
<AccordionItem value="feedback">
<AccordionTrigger>{t("about.faq.feedback.title")}</AccordionTrigger>
<AccordionTrigger>
<FaqQuestion>{t("about.faq.feedback.title")}</FaqQuestion>
</AccordionTrigger>
<AccordionContent>
<AboutDescription>
{t("about.faq.feedback.contents.0")}
</AboutDescription>
</AccordionContent>
</AccordionItem>
<AccordionItem value="support">
<AccordionTrigger>{t("about.faq.support.title")}</AccordionTrigger>
<AccordionTrigger>
<FaqQuestion>{t("about.faq.support.title")}</FaqQuestion>
</AccordionTrigger>
<AccordionContent>
<AboutDescription
className="mb-2"
Expand All @@ -139,7 +159,9 @@ export function AboutFaq() {
</AccordionContent>
</AccordionItem>
<AccordionItem value="gdpr">
<AccordionTrigger>{t("about.gdpr")}</AccordionTrigger>
<AccordionTrigger>
<FaqQuestion>{t("about.gdpr")}</FaqQuestion>
</AccordionTrigger>
<AccordionContent>
<AboutDescription>
{t("about.gdprContent")}
Expand All @@ -148,6 +170,7 @@ export function AboutFaq() {
</AccordionContent>
</AccordionItem>
</Accordion>
<div className="h-12"></div>
<ContactList />
</div>
);
Expand Down
71 changes: 70 additions & 1 deletion packages/react/src/routes/about/general.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { AboutDescription } from "@/components/about/Description";
import { AboutHeading } from "@/components/about/Heading";
import { QuickLink, QuickLinkProps } from "@/components/about/QuickLink";
import StatComponent from "@/components/about/Stats";
import { useQuery } from "@tanstack/react-query";
import { useMemo } from "react";
import { useTranslation } from "react-i18next";

Expand Down Expand Up @@ -49,11 +51,13 @@ export function AboutGeneral() {
);

return (
<article className="w-full">
<article className="w-full @container">
<AboutHeading>{t("about.general.summary.title")}</AboutHeading>
<AboutDescription>{t("about.general.summary.0")}</AboutDescription>
<AboutDescription>{t("about.general.summary.1")}</AboutDescription>
<AboutDescription>{t("about.general.summary.2")}</AboutDescription>
<AboutHeading>{t("component.channelInfo.stats")}</AboutHeading>
<StatsBlock></StatsBlock>
<AboutHeading>{t("about.quicklinks")}</AboutHeading>
<div className="grid grid-cols-[repeat(auto-fill,minmax(270px,1fr))] gap-4 pt-2">
{quickLinks.map((link) => (
Expand All @@ -77,3 +81,68 @@ export function AboutGeneral() {
</article>
);
}

interface Metrics {
statistics: {
channelCount: {
vtuber?: number;
subber?: number;
};
monthlyChannels: {
vtuber?: number;
subber?: number;
};
totalVideos: {
count?: number;
};
dailyVideos: {
count?: number;
};
totalSongs: {
count?: number;
};
};
}
function StatsBlock() {
const { data: stats, isSuccess } = useQuery<Metrics>({
queryKey: ["stats"],
queryFn: () => fetch("/statics/stats.json").then((res) => res.json()),
staleTime: 50000,
});

if (!isSuccess || !stats) {
// return a loading state using Shadcn
return <div>Loading...</div>;
}

return (
<div className="mx-auto grid w-full min-w-min grid-cols-1 gap-4 @md:max-w-2xl @md:grid-cols-2 @lg:max-w-4xl">
<StatComponent
title={"Vtubers"}
amount={stats.statistics.channelCount.vtuber || 0}
change={stats.statistics.monthlyChannels.vtuber || 0}
duration={1000}
timeText="last month"
/>
<StatComponent
title={"Subbers"}
amount={stats.statistics.channelCount.subber || 0}
change={stats.statistics.monthlyChannels.subber || 0}
duration={1000}
timeText="last month"
/>
<StatComponent
title={"Videos"}
amount={stats.statistics.totalVideos.count || 0}
change={stats.statistics.dailyVideos.count || 0}
duration={1000}
timeText="last day"
/>
<StatComponent
title={"Songs"}
amount={stats.statistics.totalSongs.count || 0}
duration={1000}
/>
</div>
);
}
4 changes: 3 additions & 1 deletion packages/react/src/shadcn/ui/button.variants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ export const buttonVariants = cva(
"bg-base-3 text-base-12 hover:bg-base-4 focus-visible:ring-primary-7 active:bg-primaryA-7",
outline:
"border border-primary-7 bg-transparent hover:border-primaryA-8 hover:bg-primaryA-5 focus-visible:ring-primary-7",
primary:
"bg-primary-9 text-base-12 hover:bg-primaryA-4 focus-visible:ring-primary-7",
secondary:
"bg-secondary-9 text-base-12 hover:bg-secondaryA-4 focus-visible:ring-secondary-7 ",
"bg-secondary-9 text-base-12 hover:bg-secondaryA-4 focus-visible:ring-secondary-7",
ghost:
"hover:bg-base-4 hover:text-base-12 focus-visible:ring-primary-7 active:bg-primaryA-7",
"ghost-yt":
Expand Down
Loading

0 comments on commit f4d5527

Please sign in to comment.