aboutsummaryrefslogtreecommitdiffstats
path: root/src/app/page.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/app/page.tsx')
-rw-r--r--src/app/page.tsx144
1 files changed, 141 insertions, 3 deletions
diff --git a/src/app/page.tsx b/src/app/page.tsx
index f8e1c1b..7a9b718 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -1,5 +1,143 @@
-import { redirect } from "next/navigation";
+"use client";
+import { useEffect, useState } from "react";
+import { FaPlay, FaMusic, FaSearch } from "react-icons/fa";
+import { MdLibraryMusic } from "react-icons/md";
+import { useAuth } from "./context/auth";
+import pb from "./lib/pocketbase";
+import {
+ Root,
+ Navbar,
+ Logo,
+ LogoIcon,
+ NavCtaLink,
+ NavLeft,
+ NavCenter,
+ SearchBox,
+ SearchInput,
+ SearchButton,
+ NavRight,
-export default function HomePage() {
- redirect("/typing");
+ GridContainer,
+ CardGrid,
+ Card,
+ ThumbnailWrapper,
+ Thumbnail,
+ PlayOverlay,
+ PlayCircle,
+ CardMeta,
+ CardInfo,
+ CardTitle,
+ CardSub,
+ EmptyState,
+ TypingGlobalStyle,
+} from "./page.styles";
+
+interface ChartRecord {
+ id: string;
+ title: string;
+ artist: string;
+ thumbnail: string;
+ lrc: string;
+ media: string;
+ offset: number;
+}
+
+
+export default function TypingPage() {
+ const { user, signOut } = useAuth();
+ const [charts, setCharts] = useState<ChartRecord[]>([]);
+ const [search, setSearch] = useState("");
+
+ useEffect(() => {
+ pb.collection("charts")
+ .getFullList<ChartRecord>({ sort: "-created" })
+ .then(setCharts)
+ .catch(console.error);
+ }, []);
+
+ const normalizedSearch = search.trim().toLowerCase();
+ const filtered = normalizedSearch
+ ? charts.filter(
+ (item) =>
+ item.title.toLowerCase().includes(normalizedSearch) ||
+ item.artist.toLowerCase().includes(normalizedSearch),
+ )
+ : charts;
+
+ return (
+ <>
+ <TypingGlobalStyle />
+ <Root>
+ <Navbar>
+ <NavLeft>
+ <Logo href="/">
+ <LogoIcon>
+ <MdLibraryMusic />
+ </LogoIcon>
+ TypingMIXX
+ </Logo>
+ </NavLeft>
+
+ <NavCenter>
+ <SearchBox>
+ <SearchInput
+ placeholder="Search typing charts..."
+ value={search}
+ onChange={(e) => setSearch(e.target.value)}
+ />
+ <SearchButton aria-label="Search">
+ <FaSearch />
+ </SearchButton>
+ </SearchBox>
+ </NavCenter>
+
+ <NavRight>
+ {user ? (
+ <>
+ <span style={{ fontSize: 13, color: "#b0b3bd", padding: "0 6px", maxWidth: 140, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
+ {user.username || user.name}
+ </span>
+ <NavCtaLink href="#" onClick={(e) => { e.preventDefault(); signOut(); }}>
+ Sign out
+ </NavCtaLink>
+ </>
+ ) : (
+ <NavCtaLink href="/signin">Sign in</NavCtaLink>
+ )}
+ </NavRight>
+ </Navbar>
+
+ <GridContainer>
+ <CardGrid>
+ {filtered.length === 0 ? (
+ <EmptyState>No results found.</EmptyState>
+ ) : (
+ filtered.map((item) => (
+ <Card key={item.id} href={`/game/${item.id}`} target="_blank" rel="noopener noreferrer">
+ <ThumbnailWrapper>
+ {item.thumbnail ? (
+ <Thumbnail src={item.thumbnail} alt={item.title} />
+ ) : (
+ <FaMusic />
+ )}
+ <PlayOverlay>
+ <PlayCircle>
+ <FaPlay />
+ </PlayCircle>
+ </PlayOverlay>
+ </ThumbnailWrapper>
+ <CardMeta>
+ <CardInfo>
+ <CardTitle>{item.title}</CardTitle>
+ <CardSub>{item.artist}</CardSub>
+ </CardInfo>
+ </CardMeta>
+ </Card>
+ ))
+ )}
+ </CardGrid>
+ </GridContainer>
+ </Root>
+ </>
+ );
}
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage