mirror of
https://github.com/AnimeThemes/animethemes-web.git
synced 2026-07-11 01:24:31 +02:00
b0724e568a
* Bumped Next.js to 15. * Bumped React to 19. * Bumped GraphQL to 16. * Bumped styled-components to 6. * Bumped Radix components to latest version. * Migrated Framer Motion to new package. * Migrated react-query to new package. * Lots of TypeScript fixes. * Removed FontAwesome Pro icons. * Started fading out SWR. * Dev Server now uses Turbopack.
114 lines
3.7 KiB
TypeScript
114 lines
3.7 KiB
TypeScript
import type { ComponentPropsWithoutRef, ReactNode } from "react";
|
|
import styled from "styled-components";
|
|
|
|
import { faAward, faSeedling, faUsers } from "@fortawesome/free-solid-svg-icons";
|
|
import gql from "graphql-tag";
|
|
|
|
import { Column } from "@/components/box/Flex";
|
|
import { SummaryCard } from "@/components/card/SummaryCard";
|
|
import { ThemeSummaryCard } from "@/components/card/ThemeSummaryCard";
|
|
import { CornerIcon } from "@/components/icon/CornerIcon";
|
|
import { Icon } from "@/components/icon/Icon";
|
|
import { Text } from "@/components/text/Text";
|
|
import { TextLink } from "@/components/text/TextLink";
|
|
import { SongTitleWithArtists } from "@/components/utils/SongTitleWithArtists";
|
|
import type { BracketThemeSummaryCardConstestantFragment } from "@/generated/graphql";
|
|
import createVideoSlug from "@/utils/createVideoSlug";
|
|
import extractImages from "@/utils/extractImages";
|
|
|
|
const StyledSummaryCardWrapper = styled.div`
|
|
position: relative;
|
|
|
|
justify-self: stretch;
|
|
`;
|
|
|
|
const StyledSummaryCard = styled(SummaryCard)`
|
|
padding-inline-end: 24px;
|
|
|
|
opacity: var(--opacity);
|
|
`;
|
|
|
|
const StyledRank = styled(Text)`
|
|
font-variant-numeric: tabular-nums;
|
|
letter-spacing: 1px;
|
|
`;
|
|
|
|
interface BracketThemeSummaryCardProps extends ComponentPropsWithoutRef<typeof StyledSummaryCardWrapper> {
|
|
contestant: BracketThemeSummaryCardConstestantFragment;
|
|
isVoted: boolean;
|
|
isWinner: boolean;
|
|
seed: number | null;
|
|
votes: number | null;
|
|
}
|
|
|
|
export function BracketThemeSummaryCard({
|
|
contestant,
|
|
isVoted,
|
|
isWinner,
|
|
seed,
|
|
votes,
|
|
...props
|
|
}: BracketThemeSummaryCardProps) {
|
|
const theme = contestant.theme;
|
|
const { smallCover } = extractImages(theme?.anime);
|
|
|
|
let to;
|
|
let description: ReactNode = contestant.source;
|
|
|
|
if (theme?.anime) {
|
|
const entry = theme.entries?.[0];
|
|
const video = entry?.videos?.[0];
|
|
const videoSlug = createVideoSlug(theme, entry, video);
|
|
|
|
to = `/anime/${theme.anime.slug}/${videoSlug}`;
|
|
|
|
description = (
|
|
<SummaryCard.Description>
|
|
<span>{theme.type + (theme.sequence || "")}</span>
|
|
<TextLink href={`/anime/${theme.anime.slug}`}>{theme.anime.name}</TextLink>
|
|
</SummaryCard.Description>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<StyledSummaryCardWrapper {...props}>
|
|
<StyledSummaryCard
|
|
title={theme ? <SongTitleWithArtists song={theme.song} songTitleLinkTo={to} /> : contestant.name}
|
|
description={description}
|
|
image={smallCover ?? contestant.image}
|
|
to={to}
|
|
style={{ "--opacity": !isVoted || isWinner ? 1 : 0.5 }}
|
|
>
|
|
<Column style={{ "--gap": "8px" }}>
|
|
<Text variant="small" color="text-muted" noWrap title="Seed">
|
|
<Icon icon={faSeedling} />
|
|
<StyledRank> {seed}</StyledRank>
|
|
</Text>
|
|
{isVoted && (
|
|
<Text variant="small" color={isWinner ? "text-primary" : "text-muted"} noWrap title="Votes">
|
|
<Icon icon={faUsers} />
|
|
<StyledRank> {votes}</StyledRank>
|
|
</Text>
|
|
)}
|
|
</Column>
|
|
</StyledSummaryCard>
|
|
{isWinner && <CornerIcon icon={faAward} title="Winner" />}
|
|
</StyledSummaryCardWrapper>
|
|
);
|
|
}
|
|
|
|
BracketThemeSummaryCard.fragments = {
|
|
contestant: gql`
|
|
${ThemeSummaryCard.fragments.theme}
|
|
|
|
fragment BracketThemeSummaryCardConstestant on BracketCharacter {
|
|
name
|
|
source
|
|
image
|
|
theme {
|
|
...ThemeSummaryCardTheme
|
|
}
|
|
}
|
|
`,
|
|
};
|