refactor: Changed all fragments to use the same format

This commit is contained in:
Maniload
2026-03-21 04:23:31 +01:00
parent 37a512ad05
commit b79b8811f0
50 changed files with 1432 additions and 1514 deletions
@@ -32,40 +32,38 @@ const StyledRank = styled(Text)`
letter-spacing: 1px;
`;
const fragments = {
theme: graphql(`
fragment BracketThemeSummaryCardTheme on AnimeTheme {
...createVideoSlugTheme
...ThemeMenuTheme
type
sequence
group {
name
slug
}
anime {
slug
name
images {
nodes {
...extractImagesImage
}
}
}
song {
...SongTitleWithArtistsSong
}
animethemeentries {
...createVideoSlugEntry
videos {
nodes {
...createVideoSlugVideo
}
export const BRACKET_THEME_SUMMARY_CARD_THEME = graphql(`
fragment BracketThemeSummaryCardTheme on AnimeTheme {
...createVideoSlugTheme
...ThemeMenuTheme
type
sequence
group {
name
slug
}
anime {
slug
name
images {
nodes {
...extractImagesImage
}
}
}
`),
};
song {
...SongTitleWithArtistsSong
}
animethemeentries {
...createVideoSlugEntry
videos {
nodes {
...createVideoSlugVideo
}
}
}
}
`);
export interface BracketWithThemes extends Bracket {
currentRound: BracketRoundWithThemes | null;
@@ -79,7 +77,7 @@ export interface BracketPairingWithThemes extends BracketPairing {
characterB: BracketCharacterWithTheme;
}
export interface BracketCharacterWithTheme extends BracketCharacter {
theme: FragmentType<typeof fragments.theme> | null;
theme: FragmentType<typeof BRACKET_THEME_SUMMARY_CARD_THEME> | null;
}
interface BracketThemeSummaryCardProps extends ComponentPropsWithoutRef<typeof StyledSummaryCardWrapper> {
@@ -98,7 +96,7 @@ export function BracketThemeSummaryCard({
votes,
...props
}: BracketThemeSummaryCardProps) {
const theme = getFragmentData(fragments.theme, character.theme);
const theme = getFragmentData(BRACKET_THEME_SUMMARY_CARD_THEME, character.theme);
const { smallCover } = extractImages(theme?.anime.images.nodes ?? []);
let to;
+33 -32
View File
@@ -11,36 +11,37 @@ import PlayerContext from "@/context/playerContext";
import { type FragmentType, getFragmentData, graphql } from "@/graphql/generated";
import createVideoSlug, { getVideoSlugByWatchListItem } from "@/utils/createVideoSlug";
const fragments = {
anime: graphql(`
fragment VideoButtonAnime on Anime {
slug
}
`),
theme: graphql(`
fragment VideoButtonTheme on AnimeTheme {
...createVideoSlugTheme
}
`),
entry: graphql(`
fragment VideoButtonEntry on AnimeThemeEntry {
...createVideoSlugEntry
}
`),
video: graphql(`
fragment VideoButtonVideo on Video {
...createVideoSlugVideo
...VideoTagsVideo
id
}
`),
};
export const VIDEO_BUTTON_ANIME = graphql(`
fragment VideoButtonAnime on Anime {
slug
}
`);
export const VIDEO_BUTTON_THEME = graphql(`
fragment VideoButtonTheme on AnimeTheme {
...createVideoSlugTheme
}
`);
export const VIDEO_BUTTON_ENTRY = graphql(`
fragment VideoButtonEntry on AnimeThemeEntry {
...createVideoSlugEntry
}
`);
export const VIDEO_BUTTON_VIDEO = graphql(`
fragment VideoButtonVideo on Video {
...createVideoSlugVideo
...VideoTagsVideo
id
}
`);
interface VideoButtonProps extends ComponentPropsWithoutRef<typeof Button> {
anime: FragmentType<typeof fragments.anime>;
theme: FragmentType<typeof fragments.theme>;
entry: FragmentType<typeof fragments.entry>;
video: FragmentType<typeof fragments.video>;
anime: FragmentType<typeof VIDEO_BUTTON_ANIME>;
theme: FragmentType<typeof VIDEO_BUTTON_THEME>;
entry: FragmentType<typeof VIDEO_BUTTON_ENTRY>;
video: FragmentType<typeof VIDEO_BUTTON_VIDEO>;
}
export function VideoButton({
@@ -50,10 +51,10 @@ export function VideoButton({
video: videoFragment,
...props
}: VideoButtonProps) {
const anime = getFragmentData(fragments.anime, animeFragment);
const theme = getFragmentData(fragments.theme, themeFragment);
const entry = getFragmentData(fragments.entry, entryFragment);
const video = getFragmentData(fragments.video, videoFragment);
const anime = getFragmentData(VIDEO_BUTTON_ANIME, animeFragment);
const theme = getFragmentData(VIDEO_BUTTON_THEME, themeFragment);
const entry = getFragmentData(VIDEO_BUTTON_ENTRY, entryFragment);
const video = getFragmentData(VIDEO_BUTTON_VIDEO, videoFragment);
const { currentWatchListItem } = useContext(PlayerContext);
const videoSlug = createVideoSlug(theme, entry, video);
+34 -35
View File
@@ -60,48 +60,47 @@ const StyledThemeGroupContainer = styled.div`
margin-top: 8px;
`;
const fragments = {
anime: graphql(`
fragment AnimeSummaryCardAnime on Anime {
slug
name
year
season
seasonLocalized
mediaFormatLocalized
animethemes {
group {
name
slug
}
}
images {
nodes {
...extractImagesImage
}
export const ANIME_SUMMARY_CARD_ANIME = graphql(`
fragment AnimeSummaryCardAnime on Anime {
slug
name
year
season
seasonLocalized
mediaFormatLocalized
animethemes {
group {
name
slug
}
}
`),
expandable: graphql(`
fragment AnimeSummaryCardAnimeExpandable on Anime {
animethemes {
...ThemeTableTheme
group {
name
slug
}
images {
nodes {
...extractImagesImage
}
}
`),
};
}
`);
export const ANIME_SUMMARY_CARD_ANIME_EXPANDABLE = graphql(`
fragment AnimeSummaryCardAnimeExpandable on Anime {
animethemes {
...ThemeTableTheme
group {
name
slug
}
}
}
`);
interface AnimeSummaryCardProps {
anime: FragmentType<typeof fragments.anime>;
expandable?: FragmentType<typeof fragments.expandable>;
anime: FragmentType<typeof ANIME_SUMMARY_CARD_ANIME>;
expandable?: FragmentType<typeof ANIME_SUMMARY_CARD_ANIME_EXPANDABLE>;
}
export function AnimeSummaryCard({ anime: animeFragment, expandable, ...props }: AnimeSummaryCardProps) {
const anime = getFragmentData(fragments.anime, animeFragment);
const anime = getFragmentData(ANIME_SUMMARY_CARD_ANIME, animeFragment);
const [isExpanded, toggleExpanded] = useToggle();
const { smallCover } = extractImages(anime.images.nodes);
const isMobile = useMediaQuery(`(max-width: ${theme.breakpoints.mobileMax})`);
@@ -164,7 +163,7 @@ export function AnimeSummaryCard({ anime: animeFragment, expandable, ...props }:
</SummaryCard>
{expandable ? (
<AnimeSummaryCardCollapse
anime={getFragmentData(fragments.expandable, expandable)}
anime={getFragmentData(ANIME_SUMMARY_CARD_ANIME_EXPANDABLE, expandable)}
isExpanded={isExpanded}
/>
) : null}
@@ -173,7 +172,7 @@ export function AnimeSummaryCard({ anime: animeFragment, expandable, ...props }:
}
interface AnimeSummaryCardCollapseProps {
anime: ResultOf<typeof fragments.expandable>;
anime: ResultOf<typeof ANIME_SUMMARY_CARD_ANIME_EXPANDABLE>;
isExpanded: boolean;
}
+11 -13
View File
@@ -2,27 +2,25 @@ import { SummaryCard } from "@/components/card/SummaryCard";
import { type FragmentType, getFragmentData, graphql } from "@/graphql/generated";
import extractImages from "@/utils/extractImages";
const fragments = {
artist: graphql(`
fragment ArtistSummaryCardArtist on Artist {
slug
name
images {
nodes {
...extractImagesImage
}
export const ARTIST_SUMMARY_CARD_ARTIST = graphql(`
fragment ArtistSummaryCardArtist on Artist {
slug
name
images {
nodes {
...extractImagesImage
}
}
`),
};
}
`);
type ArtistSummaryCardProps = {
artist: FragmentType<typeof fragments.artist>;
artist: FragmentType<typeof ARTIST_SUMMARY_CARD_ARTIST>;
as?: string | null;
};
export function ArtistSummaryCard({ artist: artistFragment, as }: ArtistSummaryCardProps) {
const artist = getFragmentData(fragments.artist, artistFragment);
const artist = getFragmentData(ARTIST_SUMMARY_CARD_ARTIST, artistFragment);
const { smallCover } = extractImages(artist.images.nodes);
+18 -19
View File
@@ -28,27 +28,26 @@ const StyledOverlayButtons = styled.div`
}
`;
const fragments = {
playlist: graphql(`
fragment PlaylistSummaryCardPlaylist on Playlist {
id
export const PLAYLIST_SUMMARY_CARD_PLAYLIST = graphql(`
fragment PlaylistSummaryCardPlaylist on Playlist {
id
name
visibilityLocalized
tracksCount
}
`);
export const PLAYLIST_SUMMARY_CARD_PLAYLIST_WITH_OWNER = graphql(`
fragment PlaylistSummaryCardPlaylistWithOwner on Playlist {
user {
name
visibilityLocalized
tracksCount
}
`),
playlistWithOwner: graphql(`
fragment PlaylistSummaryCardPlaylistWithOwner on Playlist {
user {
name
}
}
`),
};
}
`);
interface PlaylistSummaryCardProps {
playlist: FragmentType<typeof fragments.playlist>;
playlistWithOwner?: FragmentType<typeof fragments.playlistWithOwner>;
playlist: FragmentType<typeof PLAYLIST_SUMMARY_CARD_PLAYLIST>;
playlistWithOwner?: FragmentType<typeof PLAYLIST_SUMMARY_CARD_PLAYLIST_WITH_OWNER>;
menu?: ReactNode;
}
@@ -59,8 +58,8 @@ export default function PlaylistSummaryCard({
menu,
...props
}: PropsWithChildren<PlaylistSummaryCardProps>) {
const playlist = getFragmentData(fragments.playlist, playlistFragment);
const playlistWithOwner = getFragmentData(fragments.playlistWithOwner, playlistWithOwnerFragment);
const playlist = getFragmentData(PLAYLIST_SUMMARY_CARD_PLAYLIST, playlistFragment);
const playlistWithOwner = getFragmentData(PLAYLIST_SUMMARY_CARD_PLAYLIST_WITH_OWNER, playlistWithOwnerFragment);
const description = (
<SummaryCard.Description>
+11 -13
View File
@@ -7,26 +7,24 @@ import { type FragmentType, getFragmentData, graphql } from "@/graphql/generated
import extractBackgroundColor from "@/utils/extractBackgroundColor";
import extractImages from "@/utils/extractImages";
const fragments = {
studio: graphql(`
fragment StudioSummaryCardStudio on Studio {
slug
name
images {
nodes {
...extractImagesImage
}
export const STUDIO_SUMMARY_CARD_STUDIO = graphql(`
fragment StudioSummaryCardStudio on Studio {
slug
name
images {
nodes {
...extractImagesImage
}
}
`),
};
}
`);
interface StudioSummaryCardProps {
studio: FragmentType<typeof fragments.studio>;
studio: FragmentType<typeof STUDIO_SUMMARY_CARD_STUDIO>;
}
export function StudioSummaryCard({ studio: studioFragment }: StudioSummaryCardProps) {
const studio = getFragmentData(fragments.studio, studioFragment);
const studio = getFragmentData(STUDIO_SUMMARY_CARD_STUDIO, studioFragment);
const [backgroundColor, setBackgroundColor] = useState<Property.Background>();
+32 -34
View File
@@ -42,48 +42,46 @@ const StyledVideoList = styled(Row)`
}
`;
const fragments = {
theme: graphql(`
fragment ThemeDetailCardTheme on AnimeTheme {
...ThemeMenuTheme
...VideoButtonTheme
type
sequence
group {
name
slug
}
anime {
...VideoButtonAnime
slug
name
}
song {
...SongTitleSong
...PerformancesSong
}
animethemeentries {
...ThemeEntryTagsEntry
...VideoButtonEntry
version
videos {
nodes {
...VideoButtonVideo
filename
tags
}
export const THEME_DETAIL_CARD_THEME = graphql(`
fragment ThemeDetailCardTheme on AnimeTheme {
...ThemeMenuTheme
...VideoButtonTheme
type
sequence
group {
name
slug
}
anime {
...VideoButtonAnime
slug
name
}
song {
...SongTitleSong
...PerformancesSong
}
animethemeentries {
...ThemeEntryTagsEntry
...VideoButtonEntry
version
videos {
nodes {
...VideoButtonVideo
filename
tags
}
}
}
`),
};
}
`);
interface ThemeDetailCardProps {
theme: FragmentType<typeof fragments.theme>;
theme: FragmentType<typeof THEME_DETAIL_CARD_THEME>;
}
export function ThemeDetailCard({ theme: themeFragment }: ThemeDetailCardProps) {
const theme = getFragmentData(fragments.theme, themeFragment);
const theme = getFragmentData(THEME_DETAIL_CARD_THEME, themeFragment);
const { anime } = theme;
if (!anime) {
+10 -12
View File
@@ -21,23 +21,21 @@ import type { PlaylistVisibility } from "@/graphql/generated/graphql";
import { PLAYLIST_DETAIL_PAGE_PLAYLIST } from "@/pages/playlist/[playlistId]";
import { PROFILE_PAGE } from "@/pages/profile";
const fragments = {
playlist: graphql(`
fragment PlaylistEditDialogPlaylist on Playlist {
id
name
visibility
}
`),
};
export const PLAYLIST_EDIT_DIALOG_PLAYLIST = graphql(`
fragment PlaylistEditDialogPlaylist on Playlist {
id
name
visibility
}
`);
interface PlaylistEditDialogProps {
playlist: FragmentType<typeof fragments.playlist>;
playlist: FragmentType<typeof PLAYLIST_EDIT_DIALOG_PLAYLIST>;
trigger?: ReactNode;
}
export function PlaylistEditDialog({ playlist: playlistFragment, trigger }: PlaylistEditDialogProps) {
const playlist = getFragmentData(fragments.playlist, playlistFragment);
const playlist = getFragmentData(PLAYLIST_EDIT_DIALOG_PLAYLIST, playlistFragment);
const [open, setOpen] = useState(false);
@@ -71,7 +69,7 @@ const StyledForm = styled.form`
`;
interface PlaylistEditFormProps {
playlist: ResultOf<typeof fragments.playlist>;
playlist: ResultOf<typeof PLAYLIST_EDIT_DIALOG_PLAYLIST>;
onSuccess(): void;
onCancel(): void;
}
+11 -13
View File
@@ -18,24 +18,22 @@ import { useToasts } from "@/context/toastContext";
import { type FragmentType, getFragmentData, graphql } from "@/graphql/generated";
import { PROFILE_PAGE } from "@/pages/profile";
const fragments = {
playlist: graphql(`
fragment PlaylistRemoveDialogPlaylist on Playlist {
...PlaylistSummaryCardPlaylist
...PlaylistRemoveToastPlaylist
id
name
}
`),
};
export const PLAYLIST_REMOVE_DIALOG_PLAYLIST = graphql(`
fragment PlaylistRemoveDialogPlaylist on Playlist {
...PlaylistSummaryCardPlaylist
...PlaylistRemoveToastPlaylist
id
name
}
`);
interface PlaylistRemoveDialogProps {
playlist: FragmentType<typeof fragments.playlist>;
playlist: FragmentType<typeof PLAYLIST_REMOVE_DIALOG_PLAYLIST>;
trigger?: ReactNode;
}
export function PlaylistRemoveDialog({ playlist: playlistFragment, trigger }: PlaylistRemoveDialogProps) {
const playlist = getFragmentData(fragments.playlist, playlistFragment);
const playlist = getFragmentData(PLAYLIST_REMOVE_DIALOG_PLAYLIST, playlistFragment);
const [open, setOpen] = useState(false);
@@ -65,7 +63,7 @@ export function PlaylistRemoveDialog({ playlist: playlistFragment, trigger }: Pl
}
interface PlaylistRemoveFormProps {
playlist: ResultOf<typeof fragments.playlist>;
playlist: ResultOf<typeof PLAYLIST_REMOVE_DIALOG_PLAYLIST>;
onSuccess(): void;
onCancel(): void;
}
@@ -25,26 +25,25 @@ import { type FragmentType, getFragmentData, graphql } from "@/graphql/generated
import { PLAYLIST_DETAIL_PAGE_PLAYLIST } from "@/pages/playlist/[playlistId]";
import { PROFILE_PAGE } from "@/pages/profile";
const fragments = {
video: graphql(`
fragment PlaylistTrackAddDialogVideo on Video {
...VideoSummaryCardVideo
id
}
`),
entry: graphql(`
fragment PlaylistTrackAddDialogEntry on AnimeThemeEntry {
...VideoSummaryCardEntry
...PlaylistTrackAddToastEntry
...PlaylistTrackRemoveToastEntry
id
}
`),
};
export const PLAYLIST_TRACK_ADD_DIALOG_VIDEO = graphql(`
fragment PlaylistTrackAddDialogVideo on Video {
...VideoSummaryCardVideo
id
}
`);
export const PLAYLIST_TRACK_ADD_DIALOG_ENTRY = graphql(`
fragment PlaylistTrackAddDialogEntry on AnimeThemeEntry {
...VideoSummaryCardEntry
...PlaylistTrackAddToastEntry
...PlaylistTrackRemoveToastEntry
id
}
`);
interface PlaylistTrackAddDialogProps {
video: FragmentType<typeof fragments.video>;
entry: FragmentType<typeof fragments.entry>;
video: FragmentType<typeof PLAYLIST_TRACK_ADD_DIALOG_VIDEO>;
entry: FragmentType<typeof PLAYLIST_TRACK_ADD_DIALOG_ENTRY>;
trigger?: ReactNode;
}
@@ -53,8 +52,8 @@ export function PlaylistTrackAddDialog({
entry: entryFragment,
trigger,
}: PlaylistTrackAddDialogProps) {
const video = getFragmentData(fragments.video, videoFragment);
const entry = getFragmentData(fragments.entry, entryFragment);
const video = getFragmentData(PLAYLIST_TRACK_ADD_DIALOG_VIDEO, videoFragment);
const entry = getFragmentData(PLAYLIST_TRACK_ADD_DIALOG_ENTRY, entryFragment);
const [open, setOpen] = useState(false);
return (
@@ -93,8 +92,8 @@ const PLAYLIST_TRACK_ADD_FORM_PLAYLIST = graphql(`
`);
interface PlaylistTrackAddFormProps {
video: ResultOf<typeof fragments.video>;
entry: ResultOf<typeof fragments.entry>;
video: ResultOf<typeof PLAYLIST_TRACK_ADD_DIALOG_VIDEO>;
entry: ResultOf<typeof PLAYLIST_TRACK_ADD_DIALOG_ENTRY>;
onCancel(): void;
}
@@ -175,8 +174,8 @@ const PLAYLIST_TRACK_ADD_CARD_TRACK = graphql(`
interface PlaylistTrackAddCardProps {
playlist: FragmentType<typeof PLAYLIST_TRACK_ADD_CARD_PLAYLIST>;
track: FragmentType<typeof PLAYLIST_TRACK_ADD_CARD_TRACK> | null;
video: ResultOf<typeof fragments.video>;
entry: ResultOf<typeof fragments.entry>;
video: ResultOf<typeof PLAYLIST_TRACK_ADD_DIALOG_VIDEO>;
entry: ResultOf<typeof PLAYLIST_TRACK_ADD_DIALOG_ENTRY>;
}
function PlaylistTrackAddCard({
@@ -18,32 +18,32 @@ import { useToasts } from "@/context/toastContext";
import { type FragmentType, getFragmentData, graphql } from "@/graphql/generated";
import { PLAYLIST_DETAIL_PAGE_PLAYLIST } from "@/pages/playlist/[playlistId]";
const fragments = {
playlist: graphql(`
fragment PlaylistTrackRemoveDialogPlaylist on Playlist {
...PlaylistTrackRemoveToastPlaylist
id
name
}
`),
video: graphql(`
fragment PlaylistTrackRemoveDialogVideo on Video {
...VideoSummaryCardVideo
}
`),
entry: graphql(`
fragment PlaylistTrackRemoveDialogEntry on AnimeThemeEntry {
...VideoSummaryCardEntry
...PlaylistTrackRemoveToastEntry
}
`),
};
export const PLAYLIST_TRACK_REMOVE_DIALOG_PLAYLIST = graphql(`
fragment PlaylistTrackRemoveDialogPlaylist on Playlist {
...PlaylistTrackRemoveToastPlaylist
id
name
}
`);
export const PLAYLIST_TRACK_REMOVE_DIALOG_VIDEO = graphql(`
fragment PlaylistTrackRemoveDialogVideo on Video {
...VideoSummaryCardVideo
}
`);
export const PLAYLIST_TRACK_REMOVE_DIALOG_ENTRY = graphql(`
fragment PlaylistTrackRemoveDialogEntry on AnimeThemeEntry {
...VideoSummaryCardEntry
...PlaylistTrackRemoveToastEntry
}
`);
interface PlaylistTrackRemoveDialogProps {
playlist: FragmentType<typeof fragments.playlist>;
playlist: FragmentType<typeof PLAYLIST_TRACK_REMOVE_DIALOG_PLAYLIST>;
trackId: string;
video: FragmentType<typeof fragments.video>;
entry: FragmentType<typeof fragments.entry>;
video: FragmentType<typeof PLAYLIST_TRACK_REMOVE_DIALOG_VIDEO>;
entry: FragmentType<typeof PLAYLIST_TRACK_REMOVE_DIALOG_ENTRY>;
trigger?: ReactNode;
}
@@ -54,9 +54,9 @@ export function PlaylistTrackRemoveDialog({
entry: entryFragment,
trigger,
}: PlaylistTrackRemoveDialogProps) {
const playlist = getFragmentData(fragments.playlist, playlistFragment);
const video = getFragmentData(fragments.video, videoFragment);
const entry = getFragmentData(fragments.entry, entryFragment);
const playlist = getFragmentData(PLAYLIST_TRACK_REMOVE_DIALOG_PLAYLIST, playlistFragment);
const video = getFragmentData(PLAYLIST_TRACK_REMOVE_DIALOG_VIDEO, videoFragment);
const entry = getFragmentData(PLAYLIST_TRACK_REMOVE_DIALOG_ENTRY, entryFragment);
const [open, setOpen] = useState(false);
@@ -89,10 +89,10 @@ export function PlaylistTrackRemoveDialog({
}
interface PlaylistTrackRemoveFormProps {
playlist: ResultOf<typeof fragments.playlist>;
playlist: ResultOf<typeof PLAYLIST_TRACK_REMOVE_DIALOG_PLAYLIST>;
trackId: string;
video: ResultOf<typeof fragments.video>;
entry: ResultOf<typeof fragments.entry>;
video: ResultOf<typeof PLAYLIST_TRACK_REMOVE_DIALOG_VIDEO>;
entry: ResultOf<typeof PLAYLIST_TRACK_REMOVE_DIALOG_ENTRY>;
onSuccess(): void;
onCancel(): void;
}
+27 -28
View File
@@ -119,36 +119,35 @@ const StyledGrill = styled.img`
const Box = styled.div``;
const fragments = {
entry: graphql(`
fragment FeaturedThemeEntry on AnimeThemeEntry {
...VideoSummaryCardEntry
...createVideoSlugEntry
animetheme {
...createVideoSlugTheme
anime {
slug
images {
nodes {
...extractImagesImage
}
export const FEATURED_THEME_ENTRY = graphql(`
fragment FeaturedThemeEntry on AnimeThemeEntry {
...VideoSummaryCardEntry
...createVideoSlugEntry
animetheme {
...createVideoSlugTheme
anime {
slug
images {
nodes {
...extractImagesImage
}
}
}
}
`),
video: graphql(`
fragment FeaturedThemeVideo on Video {
...VideoSummaryCardVideo
...createVideoSlugVideo
basename
}
`),
};
}
`);
export const FEATURED_THEME_VIDEO = graphql(`
fragment FeaturedThemeVideo on Video {
...VideoSummaryCardVideo
...createVideoSlugVideo
basename
}
`);
interface FeaturedThemeProps {
entry: FragmentType<typeof fragments.entry>;
video: FragmentType<typeof fragments.video>;
entry: FragmentType<typeof FEATURED_THEME_ENTRY>;
video: FragmentType<typeof FEATURED_THEME_VIDEO>;
hasGrill?: boolean;
card?: ReactNode;
onPlay?(): void;
@@ -161,8 +160,8 @@ export function FeaturedTheme({
card,
onPlay,
}: FeaturedThemeProps) {
const entry = getFragmentData(fragments.entry, entryFragment);
const video = getFragmentData(fragments.video, videoFragment);
const entry = getFragmentData(FEATURED_THEME_ENTRY, entryFragment);
const video = getFragmentData(FEATURED_THEME_VIDEO, videoFragment);
const [grill, setGrill] = useState<string | null>(null);
const [featuredThemePreview] = useSetting(FeaturedThemePreview);
@@ -196,8 +195,8 @@ export function FeaturedTheme({
}
interface FeaturedThemeBackgroundProps {
entry: ResultOf<typeof fragments.entry>;
video: ResultOf<typeof fragments.video>;
entry: ResultOf<typeof FEATURED_THEME_ENTRY>;
video: ResultOf<typeof FEATURED_THEME_VIDEO>;
onPlay?(): void;
}
+13 -15
View File
@@ -8,27 +8,25 @@ import { HorizontalScroll } from "@/components/utils/HorizontalScroll";
import { type FragmentType, getFragmentData, graphql } from "@/graphql/generated";
import { either, themeGroupComparator, themeIndexComparator, themeTypeComparator } from "@/utils/comparators";
const fragments = {
theme: graphql(`
fragment AnimeThemeFilterTheme on AnimeTheme {
...ThemeDetailCardTheme
id
type
sequence
group {
name
slug
}
export const ANIME_THEME_FILTER_THEME = graphql(`
fragment AnimeThemeFilterTheme on AnimeTheme {
...ThemeDetailCardTheme
id
type
sequence
group {
name
slug
}
`),
};
}
`);
interface AnimeThemeFilterProps {
themes: Array<FragmentType<typeof fragments.theme>>;
themes: Array<FragmentType<typeof ANIME_THEME_FILTER_THEME>>;
}
function AnimeThemeFilterInternal({ themes: themesFragment }: AnimeThemeFilterProps) {
const themes = getFragmentData(fragments.theme, themesFragment);
const themes = getFragmentData(ANIME_THEME_FILTER_THEME, themesFragment);
const hasMultipleTypes = themes.some((theme) => theme.type === "OP") && themes.some((theme) => theme.type === "ED");
const [filterType, setFilterType] = useState<string | null>(null);
+8 -10
View File
@@ -2,22 +2,20 @@ import md5 from "md5";
import { type FragmentType, getFragmentData, graphql } from "@/graphql/generated";
const fragments = {
user: graphql(`
fragment ProfileImageUser on Me {
name
email
}
`),
};
export const PROFILE_IMAGE_USER = graphql(`
fragment ProfileImageUser on Me {
name
email
}
`);
interface ProfileImageProps {
user: FragmentType<typeof fragments.user>;
user: FragmentType<typeof PROFILE_IMAGE_USER>;
size?: number;
}
export function ProfileImage({ user: userFragment, size = 80, ...props }: ProfileImageProps) {
const user = getFragmentData(fragments.user, userFragment);
const user = getFragmentData(PROFILE_IMAGE_USER, userFragment);
const hash = md5(user.email.trim().toLowerCase());
+16 -18
View File
@@ -13,34 +13,32 @@ const StyledImage = styled(FullWidthImage)`
background-size: contain;
`;
const fragments = {
studio: graphql(`
fragment StudioCoverImageStudio on Studio {
images {
nodes {
...extractImagesImage
}
export const STUDIO_COVER_IMAGE_STUDIO = graphql(`
fragment StudioCoverImageStudio on Studio {
images {
nodes {
...extractImagesImage
}
anime {
nodes {
name
images {
nodes {
...extractImagesImage
}
}
anime {
nodes {
name
images {
nodes {
...extractImagesImage
}
}
}
}
`),
};
}
`);
interface StudioCoverImageProps extends ComponentPropsWithoutRef<typeof FullWidthImage> {
studio: FragmentType<typeof fragments.studio>;
studio: FragmentType<typeof STUDIO_COVER_IMAGE_STUDIO>;
}
export function StudioCoverImage({ studio: studioFragment, ...props }: StudioCoverImageProps) {
const studio = getFragmentData(fragments.studio, studioFragment);
const studio = getFragmentData(STUDIO_COVER_IMAGE_STUDIO, studioFragment);
const { largeCover } = extractImages(studio.images.nodes);
const [imageNotFound, setImageNotFound] = useState(!largeCover);
+33 -35
View File
@@ -10,53 +10,51 @@ import { Text } from "@/components/text/Text";
import PlayerContext from "@/context/playerContext";
import { type FragmentType, getFragmentData, graphql } from "@/graphql/generated";
const fragments = {
theme: graphql(`
fragment ThemeMenuTheme on AnimeTheme {
...createVideoSlugTheme
id
type
sequence
group {
name
slug
}
anime {
slug
name
images {
nodes {
...extractImagesImage
}
export const THEME_MENU_THEME = graphql(`
fragment ThemeMenuTheme on AnimeTheme {
...createVideoSlugTheme
id
type
sequence
group {
name
slug
}
anime {
slug
name
images {
nodes {
...extractImagesImage
}
}
song {
...SongTitleWithArtistsSong
}
animethemeentries {
...createVideoSlugEntry
id
videos {
nodes {
...createVideoSlugVideo
id
}
song {
...SongTitleWithArtistsSong
}
animethemeentries {
...createVideoSlugEntry
id
videos {
nodes {
...createVideoSlugVideo
id
basename
audio {
basename
audio {
basename
}
}
}
}
}
`),
};
}
`);
interface ThemeMenuProps {
theme: FragmentType<typeof fragments.theme>;
theme: FragmentType<typeof THEME_MENU_THEME>;
}
export function ThemeMenu({ theme: themeFragment }: ThemeMenuProps) {
const theme = getFragmentData(fragments.theme, themeFragment);
const theme = getFragmentData(THEME_MENU_THEME, themeFragment);
const { watchList, addWatchListItem, addWatchListItemNext } = useContext(PlayerContext);
+38 -39
View File
@@ -10,57 +10,56 @@ import { Text } from "@/components/text/Text";
import PlayerContext from "@/context/playerContext";
import { type FragmentType, getFragmentData, graphql } from "@/graphql/generated";
const fragments = {
entry: graphql(`
fragment VideoMenuEntry on AnimeThemeEntry {
...createVideoSlugEntry
...PlaylistTrackAddDialogEntry
export const VIDEO_MENU_ENTRY = graphql(`
fragment VideoMenuEntry on AnimeThemeEntry {
...createVideoSlugEntry
...PlaylistTrackAddDialogEntry
id
animetheme {
...createVideoSlugTheme
id
animetheme {
...createVideoSlugTheme
id
type
sequence
group {
name
slug
}
anime {
slug
name
images {
nodes {
...extractImagesImage
}
type
sequence
group {
name
slug
}
anime {
slug
name
images {
nodes {
...extractImagesImage
}
}
song {
...SongTitleWithArtistsSong
}
}
song {
...SongTitleWithArtistsSong
}
}
`),
video: graphql(`
fragment VideoMenuVideo on Video {
...createVideoSlugVideo
...PlaylistTrackAddDialogVideo
id
}
`);
export const VIDEO_MENU_VIDEO = graphql(`
fragment VideoMenuVideo on Video {
...createVideoSlugVideo
...PlaylistTrackAddDialogVideo
id
basename
audio {
basename
audio {
basename
}
}
`),
};
}
`);
interface VideoMenuProps {
entry: FragmentType<typeof fragments.entry>;
video: FragmentType<typeof fragments.video>;
entry: FragmentType<typeof VIDEO_MENU_ENTRY>;
video: FragmentType<typeof VIDEO_MENU_VIDEO>;
}
export function VideoMenu({ entry: entryFragment, video: videoFragment }: VideoMenuProps) {
const entry = getFragmentData(fragments.entry, entryFragment);
const video = getFragmentData(fragments.video, videoFragment);
const entry = getFragmentData(VIDEO_MENU_ENTRY, entryFragment);
const video = getFragmentData(VIDEO_MENU_VIDEO, videoFragment);
const { watchList, addWatchListItem, addWatchListItemNext } = useContext(PlayerContext);
+17 -18
View File
@@ -5,31 +5,30 @@ import { Switcher, SwitcherOption } from "@/components/switcher/Switcher";
import { HorizontalScroll } from "@/components/utils/HorizontalScroll";
import { type FragmentType, getFragmentData, graphql } from "@/graphql/generated";
const fragments = {
year: graphql(`
fragment SeasonNavigationYear on AnimeYear {
year
seasons {
season
seasonLocalized
}
}
`),
season: graphql(`
fragment SeasonNavigationSeason on AnimeYearSeason {
export const SEASON_NAVIGATION_YEAR = graphql(`
fragment SeasonNavigationYear on AnimeYear {
year
seasons {
season
seasonLocalized
}
`),
};
}
`);
export const SEASON_NAVIGATION_SEASON = graphql(`
fragment SeasonNavigationSeason on AnimeYearSeason {
season
}
`);
interface SeasonNavigationProps {
year: FragmentType<typeof fragments.year>;
season?: FragmentType<typeof fragments.season>;
year: FragmentType<typeof SEASON_NAVIGATION_YEAR>;
season?: FragmentType<typeof SEASON_NAVIGATION_SEASON>;
}
export function SeasonNavigation({ year: yearFragment, season: seasonFragment }: SeasonNavigationProps) {
const year = getFragmentData(fragments.year, yearFragment);
const season = seasonFragment ? getFragmentData(fragments.season, seasonFragment) : undefined;
const year = getFragmentData(SEASON_NAVIGATION_YEAR, yearFragment);
const season = seasonFragment ? getFragmentData(SEASON_NAVIGATION_SEASON, seasonFragment) : undefined;
return (
<Row style={{ "--justify-content": "center" }}>
+18 -19
View File
@@ -22,31 +22,30 @@ const StyledYearNext = styled(StyledYear)`
justify-content: flex-start;
`;
const fragments = {
year: graphql(`
fragment YearNavigationYear on AnimeYear {
year
seasons {
season
seasonLocalized
}
export const YEAR_NAVIGATION_YEAR = graphql(`
fragment YearNavigationYear on AnimeYear {
year
seasons {
season
seasonLocalized
}
`),
years: graphql(`
fragment YearNavigationYears on AnimeYear {
year
}
`),
};
}
`);
export const YEAR_NAVIGATION_YEARS = graphql(`
fragment YearNavigationYears on AnimeYear {
year
}
`);
interface YearNavigationProps {
year: FragmentType<typeof fragments.year>;
years: Array<FragmentType<typeof fragments.years>>;
year: FragmentType<typeof YEAR_NAVIGATION_YEAR>;
years: Array<FragmentType<typeof YEAR_NAVIGATION_YEARS>>;
}
export function YearNavigation({ year: yearFragment, years: yearsFragment }: YearNavigationProps) {
const year = getFragmentData(fragments.year, yearFragment);
const years = getFragmentData(fragments.years, yearsFragment);
const year = getFragmentData(YEAR_NAVIGATION_YEAR, yearFragment);
const years = getFragmentData(YEAR_NAVIGATION_YEARs, yearsFragment);
const previousYear = years.find((y) => y.year === year.year - 1)?.year ?? null;
const nextYear = years.find((y) => y.year === year.year + 1)?.year ?? null;
+25 -27
View File
@@ -11,42 +11,40 @@ import { type FragmentType, getFragmentData, graphql } from "@/graphql/generated
import { either, themeIndexComparator, themeTypeComparator } from "@/utils/comparators";
import createVideoSlug from "@/utils/createVideoSlug";
const fragments = {
theme: graphql(`
fragment ThemeTableTheme on AnimeTheme {
...createVideoSlugTheme
id
type
sequence
anime {
slug
}
animethemeentries {
...createVideoSlugEntry
...EpisodeTagEntry
...ContentWarningTagsEntry
version
videos {
nodes {
...createVideoSlugVideo
...VideoTagsVideo
}
export const THEME_TABLE_THEME = graphql(`
fragment ThemeTableTheme on AnimeTheme {
...createVideoSlugTheme
id
type
sequence
anime {
slug
}
animethemeentries {
...createVideoSlugEntry
...EpisodeTagEntry
...ContentWarningTagsEntry
version
videos {
nodes {
...createVideoSlugVideo
...VideoTagsVideo
}
}
song {
...SongTitleSong
}
}
`),
};
song {
...SongTitleSong
}
}
`);
export interface ThemeTableProps {
themes: Array<FragmentType<typeof fragments.theme>>;
themes: Array<FragmentType<typeof THEME_TABLE_THEME>>;
onPlay?(initiatingThemeId: number, entryIndex?: number, videoIndex?: number): void;
}
export function ThemeTable({ themes: themesFragment, onPlay }: ThemeTableProps) {
const themes = getFragmentData(fragments.theme, themesFragment);
const themes = getFragmentData(THEME_TABLE_THEME, themesFragment);
const rows = themes
.filter(
+8 -10
View File
@@ -4,21 +4,19 @@ import { Icon } from "@/components/icon/Icon";
import { Tag } from "@/components/tag/Tag";
import { type FragmentType, getFragmentData, graphql } from "@/graphql/generated";
const fragments = {
entry: graphql(`
fragment ContentWarningTagsEntry on AnimeThemeEntry {
spoiler
nsfw
}
`),
};
export const CONTENT_WARNING_TAGS_ENTRY = graphql(`
fragment ContentWarningTagsEntry on AnimeThemeEntry {
spoiler
nsfw
}
`);
interface ContentWarningTagsProps {
entry: FragmentType<typeof fragments.entry>;
entry: FragmentType<typeof CONTENT_WARNING_TAGS_ENTRY>;
}
export function ContentWarningTags({ entry: entryFragment }: ContentWarningTagsProps) {
const entry = getFragmentData(fragments.entry, entryFragment);
const entry = getFragmentData(CONTENT_WARNING_TAGS_ENTRY, entryFragment);
return (
<>
+7 -9
View File
@@ -3,20 +3,18 @@ import { faFilm } from "@fortawesome/free-solid-svg-icons";
import { Tag } from "@/components/tag/Tag";
import { type FragmentType, getFragmentData, graphql } from "@/graphql/generated";
const fragments = {
entry: graphql(`
fragment EpisodeTagEntry on AnimeThemeEntry {
episodes
}
`),
};
export const EPISODE_TAG_ENTRY = graphql(`
fragment EpisodeTagEntry on AnimeThemeEntry {
episodes
}
`);
interface EpisodeTagProps {
entry: FragmentType<typeof fragments.entry>;
entry: FragmentType<typeof EPISODE_TAG_ENTRY>;
}
export function EpisodeTag({ entry: entryFragment }: EpisodeTagProps) {
const entry = getFragmentData(fragments.entry, entryFragment);
const entry = getFragmentData(EPISODE_TAG_ENTRY, entryFragment);
return (
<Tag icon={faFilm} title={entry.episodes ? `Used in episode ${entry.episodes}` : "Used in all episodes"}>
+8 -10
View File
@@ -3,21 +3,19 @@ import { ContentWarningTags } from "@/components/tag/ContentWarningTags";
import { EpisodeTag } from "@/components/tag/EpisodeTag";
import { type FragmentType, getFragmentData, graphql } from "@/graphql/generated";
const fragments = {
entry: graphql(`
fragment ThemeEntryTagsEntry on AnimeThemeEntry {
...EpisodeTagEntry
...ContentWarningTagsEntry
}
`),
};
export const THEME_ENTRY_TAGS_ENTRY = graphql(`
fragment ThemeEntryTagsEntry on AnimeThemeEntry {
...EpisodeTagEntry
...ContentWarningTagsEntry
}
`);
interface ThemeEntryTagsProps {
entry: FragmentType<typeof fragments.entry>;
entry: FragmentType<typeof THEME_ENTRY_TAGS_ENTRY>;
}
export function ThemeEntryTags({ entry: entryFragment }: ThemeEntryTagsProps) {
const entry = getFragmentData(fragments.entry, entryFragment);
const entry = getFragmentData(THEME_ENTRY_TAGS_ENTRY, entryFragment);
return (
<Row style={{ "--gap": "8px", "--align-items": "baseline" }}>
+13 -15
View File
@@ -11,26 +11,24 @@ const StyledVideoTags = styled(Row)`
gap: 8px;
`;
const fragments = {
video: graphql(`
fragment VideoTagsVideo on Video {
resolution
nc
subbed
lyrics
uncen
source
overlap
}
`),
};
export const VIDEO_TAGS_VIDEO = graphql(`
fragment VideoTagsVideo on Video {
resolution
nc
subbed
lyrics
uncen
source
overlap
}
`);
interface VideoTagsProps {
video: FragmentType<typeof fragments.video>;
video: FragmentType<typeof VIDEO_TAGS_VIDEO>;
}
export function VideoTags(props: VideoTagsProps) {
const video = getFragmentData(fragments.video, props.video);
const video = getFragmentData(VIDEO_TAGS_VIDEO, props.video);
return (
<StyledVideoTags>
+8 -10
View File
@@ -2,21 +2,19 @@ import { Text } from "@/components/text/Text";
import { Toast } from "@/components/toast/Toast";
import { type FragmentType, getFragmentData, graphql } from "@/graphql/generated";
const fragments = {
playlist: graphql(`
fragment PlaylistRemoveToastPlaylist on Playlist {
id
name
}
`),
};
export const PLAYLIST_REMOVE_TOAST_PLAYLIST = graphql(`
fragment PlaylistRemoveToastPlaylist on Playlist {
id
name
}
`);
interface PlaylistRemoveToastProps {
playlist: FragmentType<typeof fragments.playlist>;
playlist: FragmentType<typeof PLAYLIST_REMOVE_TOAST_PLAYLIST>;
}
export function PlaylistRemoveToast({ playlist: playlistFragment }: PlaylistRemoveToastProps) {
const playlist = getFragmentData(fragments.playlist, playlistFragment);
const playlist = getFragmentData(PLAYLIST_REMOVE_TOAST_PLAYLIST, playlistFragment);
return (
<Toast>
+18 -19
View File
@@ -6,35 +6,34 @@ import { Toast } from "@/components/toast/Toast";
import { SongTitle } from "@/components/utils/SongTitle";
import { type FragmentType, getFragmentData, graphql } from "@/graphql/generated";
const fragments = {
playlist: graphql(`
fragment PlaylistTrackAddToastPlaylist on Playlist {
id
name
}
`),
entry: graphql(`
fragment PlaylistTrackAddToastEntry on AnimeThemeEntry {
animetheme {
song {
...SongTitleSong
}
export const PLAYLIST_TRACK_ADD_TOAST_PLAYLIST = graphql(`
fragment PlaylistTrackAddToastPlaylist on Playlist {
id
name
}
`);
export const PLAYLIST_TRACK_ADD_TOAST_ENTRY = graphql(`
fragment PlaylistTrackAddToastEntry on AnimeThemeEntry {
animetheme {
song {
...SongTitleSong
}
}
`),
};
}
`);
interface PlaylistTrackAddToastProps {
playlist: FragmentType<typeof fragments.playlist>;
entry: FragmentType<typeof fragments.entry>;
playlist: FragmentType<typeof PLAYLIST_TRACK_ADD_TOAST_PLAYLIST>;
entry: FragmentType<typeof PLAYLIST_TRACK_ADD_TOAST_ENTRY>;
}
export function PlaylistTrackAddToast({
playlist: playlistFragment,
entry: entryFragment,
}: PlaylistTrackAddToastProps) {
const playlist = getFragmentData(fragments.playlist, playlistFragment);
const entry = getFragmentData(fragments.entry, entryFragment);
const playlist = getFragmentData(PLAYLIST_TRACK_ADD_TOAST_PLAYLIST, playlistFragment);
const entry = getFragmentData(PLAYLIST_TRACK_ADD_TOAST_ENTRY, entryFragment);
return (
<Toast as={Link} href={`/playlist/${playlist.id}`} $hoverable>
@@ -6,35 +6,34 @@ import { Toast } from "@/components/toast/Toast";
import { SongTitle } from "@/components/utils/SongTitle";
import { type FragmentType, getFragmentData, graphql } from "@/graphql/generated";
const fragments = {
playlist: graphql(`
fragment PlaylistTrackRemoveToastPlaylist on Playlist {
id
name
}
`),
entry: graphql(`
fragment PlaylistTrackRemoveToastEntry on AnimeThemeEntry {
animetheme {
song {
...SongTitleSong
}
export const PLAYLIST_TRACK_REMOVE_TOAST_PLAYLIST = graphql(`
fragment PlaylistTrackRemoveToastPlaylist on Playlist {
id
name
}
`);
export const PLAYLIST_TRACK_REMOVE_TOAST_ENTRY = graphql(`
fragment PlaylistTrackRemoveToastEntry on AnimeThemeEntry {
animetheme {
song {
...SongTitleSong
}
}
`),
};
}
`);
interface PlaylistTrackRemoveToastProps {
playlist: FragmentType<typeof fragments.playlist>;
entry: FragmentType<typeof fragments.entry>;
playlist: FragmentType<typeof PLAYLIST_TRACK_REMOVE_TOAST_PLAYLIST>;
entry: FragmentType<typeof PLAYLIST_TRACK_REMOVE_TOAST_ENTRY>;
}
export function PlaylistTrackRemoveToast({
playlist: playlistFragment,
entry: entryFragment,
}: PlaylistTrackRemoveToastProps) {
const playlist = getFragmentData(fragments.playlist, playlistFragment);
const entry = getFragmentData(fragments.entry, entryFragment);
const playlist = getFragmentData(PLAYLIST_TRACK_REMOVE_TOAST_PLAYLIST, playlistFragment);
const entry = getFragmentData(PLAYLIST_TRACK_REMOVE_TOAST_ENTRY, entryFragment);
return (
<Toast as={Link} href={`/playlist/${playlist.id}`} $hoverable>
+25 -26
View File
@@ -21,38 +21,37 @@ const StyledArtistLink = styled(Text).attrs({ as: "a", link: true })`
font-size: 1rem;
`;
const fragments = {
song: graphql(`
fragment PerformancesSong on Song {
performances {
alias
as
artist {
__typename
... on Artist {
export const PERFORMANCES_SONG = graphql(`
fragment PerformancesSong on Song {
performances {
alias
as
artist {
__typename
... on Artist {
slug
name
}
... on Membership {
group {
slug
name
}
... on Membership {
group {
slug
name
}
}
}
}
}
`),
artist: graphql(`
fragment PerformancesArtist on Artist {
slug
}
`),
};
}
`);
export const PERFORMANCES_ARTIST = graphql(`
fragment PerformancesArtist on Artist {
slug
}
`);
export interface PerformancesProps {
song: FragmentType<typeof fragments.song> | null;
artist?: FragmentType<typeof fragments.artist>;
song: FragmentType<typeof PERFORMANCES_SONG> | null;
artist?: FragmentType<typeof PERFORMANCES_ARTIST>;
maxPerformances?: number | null;
expandable?: boolean;
}
@@ -82,8 +81,8 @@ export function Performances({
maxPerformances = 3,
expandable = false,
}: PerformancesProps) {
const song = getFragmentData(fragments.song, songFragment);
const artist = getFragmentData(fragments.artist, artistFragment);
const song = getFragmentData(PERFORMANCES_SONG, songFragment);
const artist = getFragmentData(PERFORMANCES_ARTIST, artistFragment);
const [expandPerformances, setExpandPerformances] = useState(false);
if (!song?.performances.length) {
+7 -9
View File
@@ -4,21 +4,19 @@ import Link from "next/link";
import { Text } from "@/components/text/Text";
import { type FragmentType, getFragmentData, graphql } from "@/graphql/generated";
const fragments = {
song: graphql(`
fragment SongTitleSong on Song {
title
}
`),
};
export const SONG_TITLE_SONG = graphql(`
fragment SongTitleSong on Song {
title
}
`);
export interface SongTitleProps extends ComponentPropsWithoutRef<typeof Text> {
song: FragmentType<typeof fragments.song> | null;
song: FragmentType<typeof SONG_TITLE_SONG> | null;
href?: ComponentPropsWithoutRef<typeof Link>["href"];
}
export function SongTitle({ song: songFragment, href, ...props }: SongTitleProps) {
const song = getFragmentData(fragments.song, songFragment);
const song = getFragmentData(SONG_TITLE_SONG, songFragment);
const songTitle = song?.title || "T.B.A.";
if (href) {
+16 -17
View File
@@ -3,24 +3,23 @@ import { Performances } from "@/components/utils/Performances";
import { SongTitle } from "@/components/utils/SongTitle";
import { type FragmentType, getFragmentData, graphql } from "@/graphql/generated";
const fragments = {
song: graphql(`
fragment SongTitleWithArtistsSong on Song {
...SongTitleSong
...PerformancesSong
}
`),
artist: graphql(`
fragment SongTitleWithArtistsArtist on Artist {
...PerformancesArtist
}
`),
};
export const SONG_TITLE_WITH_ARTISTS_SONG = graphql(`
fragment SongTitleWithArtistsSong on Song {
...SongTitleSong
...PerformancesSong
}
`);
export const SONG_TITLE_WITH_ARTISTS_ARTIST = graphql(`
fragment SongTitleWithArtistsArtist on Artist {
...PerformancesArtist
}
`);
interface SongTitleWithArtistsProps {
song: FragmentType<typeof fragments.song> | null;
song: FragmentType<typeof SONG_TITLE_WITH_ARTISTS_SONG> | null;
songTitleLinkTo?: string;
artist?: FragmentType<typeof fragments.artist>;
artist?: FragmentType<typeof SONG_TITLE_WITH_ARTISTS_ARTIST>;
onPlay?: () => void;
}
@@ -31,8 +30,8 @@ export function SongTitleWithArtists({
artist: artistFragment,
onPlay,
}: SongTitleWithArtistsProps) {
const song = getFragmentData(fragments.song, songFragment);
const artist = getFragmentData(fragments.artist, artistFragment);
const song = getFragmentData(SONG_TITLE_WITH_ARTISTS_SONG, songFragment);
const artist = getFragmentData(SONG_TITLE_WITH_ARTISTS_ARTIST, artistFragment);
return (
<Text onClick={onPlay}>
+30 -31
View File
@@ -28,39 +28,38 @@ import createVideoSlug from "@/utils/createVideoSlug";
import extractImages from "@/utils/extractImages";
import { AudioMode, GlobalVolume, Muted } from "@/utils/settings";
const fragments = {
video: graphql(`
fragment VideoPlayerVideo on Video {
...VideoPlayerBarVideo
...createVideoSlugVideo
export const VIDEO_PLAYER_VIDEO = graphql(`
fragment VideoPlayerVideo on Video {
...VideoPlayerBarVideo
...createVideoSlugVideo
basename
audio {
basename
audio {
basename
}
}
`),
entry: graphql(`
fragment VideoPlayerEntry on AnimeThemeEntry {
...VideoPlayerBarEntry
...createVideoSlugEntry
animetheme {
...createVideoSlugTheme
anime {
slug
images {
nodes {
...extractImagesImage
}
}
`);
export const VIDEO_PLAYER_ENTRY = graphql(`
fragment VideoPlayerEntry on AnimeThemeEntry {
...VideoPlayerBarEntry
...createVideoSlugEntry
animetheme {
...createVideoSlugTheme
anime {
slug
images {
nodes {
...extractImagesImage
}
}
}
}
`),
};
}
`);
interface VideoPlayerContextValue {
video: ResultOf<typeof fragments.video>;
entry: ResultOf<typeof fragments.entry>;
video: ResultOf<typeof VIDEO_PLAYER_VIDEO>;
entry: ResultOf<typeof VIDEO_PLAYER_ENTRY>;
background: boolean;
videoPagePath: string;
playerRef: RefObject<HTMLVideoElement | HTMLAudioElement | null>;
@@ -89,8 +88,8 @@ type VideoPlayerProps = {
export function VideoPlayer({ watchListItem, background, children, overlay, ...props }: VideoPlayerProps) {
const { video: videoFragment, entry: entryFragment } = watchListItem;
const video = getFragmentData(fragments.video, videoFragment);
const entry = getFragmentData(fragments.entry, entryFragment);
const video = getFragmentData(VIDEO_PLAYER_VIDEO, videoFragment);
const entry = getFragmentData(VIDEO_PLAYER_ENTRY, entryFragment);
const theme = entry.animetheme;
const anime = theme.anime;
@@ -131,8 +130,8 @@ export function VideoPlayer({ watchListItem, background, children, overlay, ...p
const playbackAreaMouseRelaxProps = useMouseRelax();
const previousWatchListItem = getRelativeWatchListItem(-1);
const previousVideo = getFragmentData(fragments.video, previousWatchListItem?.video);
const previousEntry = getFragmentData(fragments.entry, previousWatchListItem?.entry);
const previousVideo = getFragmentData(VIDEO_PLAYER_VIDEO, previousWatchListItem?.video);
const previousEntry = getFragmentData(VIDEO_PLAYER_ENTRY, previousWatchListItem?.entry);
const previousTheme = previousEntry?.animetheme;
const previousAnime = previousTheme?.anime;
@@ -154,8 +153,8 @@ export function VideoPlayer({ watchListItem, background, children, overlay, ...p
);
const nextWatchListItem = getRelativeWatchListItem(1);
const nextVideo = getFragmentData(fragments.video, nextWatchListItem?.video);
const nextEntry = getFragmentData(fragments.entry, nextWatchListItem?.entry);
const nextVideo = getFragmentData(VIDEO_PLAYER_VIDEO, nextWatchListItem?.video);
const nextEntry = getFragmentData(VIDEO_PLAYER_ENTRY, nextWatchListItem?.entry);
const nextTheme = nextEntry?.animetheme;
const nextAnime = nextTheme?.anime;
+29 -30
View File
@@ -86,37 +86,36 @@ const StyledVolumeControl = styled(VolumeControl)`
margin-right: auto;
`;
const fragments = {
video: graphql(`
fragment VideoPlayerBarVideo on Video {
__typename
# ...PlaylistTrackAddDialogVideo
}
`),
entry: graphql(`
fragment VideoPlayerBarEntry on AnimeThemeEntry {
# ...PlaylistTrackAddDialogEntry
animetheme {
type
sequence
song {
...SongTitleSong
...PerformancesSong
performances {
__typename
}
}
group {
name
}
anime {
slug
name
export const VIDEO_PLAYER_BAR_VIDEO = graphql(`
fragment VideoPlayerBarVideo on Video {
__typename
# ...PlaylistTrackAddDialogVideo
}
`);
export const VIDEO_PLAYER_BAR_ENTRY = graphql(`
fragment VideoPlayerBarEntry on AnimeThemeEntry {
# ...PlaylistTrackAddDialogEntry
animetheme {
type
sequence
song {
...SongTitleSong
...PerformancesSong
performances {
__typename
}
}
group {
name
}
anime {
slug
name
}
}
`),
};
}
`);
export function VideoPlayerBar() {
const context = useContext(VideoPlayerContext);
@@ -140,8 +139,8 @@ export function VideoPlayerBar() {
audioUrl,
} = context;
const video = getFragmentData(fragments.video, videoFragment);
const entry = getFragmentData(fragments.entry, entryFragment);
const video = getFragmentData(VIDEO_PLAYER_BAR_VIDEO, videoFragment);
const entry = getFragmentData(VIDEO_PLAYER_BAR_ENTRY, entryFragment);
const theme = entry.animetheme;
const anime = theme.anime;
+8 -10
View File
@@ -16,22 +16,20 @@ const StyledCodeBlock = styled.pre`
}
`;
const fragments = {
video: graphql(`
fragment VideoScriptVideo on Video {
videoscript {
link
}
export const VIDEO_SCRIPT_VIDEO = graphql(`
fragment VideoScriptVideo on Video {
videoscript {
link
}
`),
};
}
`);
interface Props {
video: FragmentType<typeof fragments.video>;
video: FragmentType<typeof VIDEO_SCRIPT_VIDEO>;
}
export default function VideoScript({ video: videoFragment }: Props) {
const video = getFragmentData(fragments.video, videoFragment);
const video = getFragmentData(VIDEO_SCRIPT_VIDEO, videoFragment);
const [isLoading, setLoading] = useState(false);
const [videoScript, setVideoScript] = useState<string>();
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+8 -10
View File
@@ -45,14 +45,12 @@ const ArrowLink = styled(Link)`
gap: 8px;
`;
const fragments = {
page: graphql(`
fragment DocumentPagePage on Page {
name
createdAt
}
`),
};
export const DOCUMENT_PAGE_PAGE = graphql(`
fragment DocumentPagePage on Page {
name
createdAt
}
`);
const propsQuery = graphql(`
query DocumentPage($pageSlug: String!) {
@@ -74,7 +72,7 @@ const pathsQuery = graphql(`
`);
export interface DocumentPageProps extends SharedPageProps {
page: FragmentType<typeof fragments.page>;
page: FragmentType<typeof DOCUMENT_PAGE_PAGE>;
source: MDXRemoteSerializeResult;
headings: Heading[];
}
@@ -84,7 +82,7 @@ interface DocumentPageParams extends ParsedUrlQuery {
}
export default function DocumentPage({ page: pageFragment, source, headings }: DocumentPageProps) {
const page = getFragmentData(fragments.page, pageFragment);
const page = getFragmentData(DOCUMENT_PAGE_PAGE, pageFragment);
const author = typeof source.frontmatter?.author === "string" ? source.frontmatter.author : undefined;
return (
@@ -31,97 +31,95 @@ import fetchStaticPaths from "@/utils/fetchStaticPaths";
import type { SharedPageProps } from "@/utils/getSharedPageProps";
import getSharedPageProps from "@/utils/getSharedPageProps";
const fragments = {
anime: graphql(`
fragment VideoPageAnime on Anime {
...AnimeSummaryCardAnime
name
slug
year
season
animethemes {
...ThemeSummaryCardTheme
...createVideoSlugTheme
id
type
sequence
song {
title
performances {
artist {
...ArtistSummaryCardArtist
}
as
export const VIDEO_PAGE_ANIME = graphql(`
fragment VideoPageAnime on Anime {
...AnimeSummaryCardAnime
name
slug
year
season
animethemes {
...ThemeSummaryCardTheme
...createVideoSlugTheme
id
type
sequence
song {
title
performances {
artist {
...ArtistSummaryCardArtist
}
as
}
group {
slug
}
animethemeentries {
...VideoPlayerEntry
...createVideoSlugEntry
id
episodes
nsfw
spoiler
version
videos {
nodes {
...VideoPlayerVideo
...VideoScriptVideo
...createVideoSlugVideo
id
basename
filename
lyrics
nc
overlap
resolution
source
subbed
uncen
tags
animethemeentries {
nodes {
animetheme {
...ThemeSummaryCardTheme
anime {
slug
}
}
group {
slug
}
animethemeentries {
...VideoPlayerEntry
...createVideoSlugEntry
id
episodes
nsfw
spoiler
version
videos {
nodes {
...VideoPlayerVideo
...VideoScriptVideo
...createVideoSlugVideo
id
basename
filename
lyrics
nc
overlap
resolution
source
subbed
uncen
tags
animethemeentries {
nodes {
animetheme {
...ThemeSummaryCardTheme
anime {
slug
}
}
}
tracks {
playlist {
...PlaylistSummaryCardPlaylist
...PlaylistSummaryCardPlaylistWithOwner
id
}
}
tracks {
playlist {
...PlaylistSummaryCardPlaylist
...PlaylistSummaryCardPlaylistWithOwner
id
}
}
}
}
}
images {
nodes {
...extractImagesImage
}
}
series {
nodes {
slug
name
}
}
studios {
nodes {
...StudioSummaryCardStudio
slug
}
}
images {
nodes {
...extractImagesImage
}
}
`),
};
series {
nodes {
slug
name
}
}
studios {
nodes {
...StudioSummaryCardStudio
slug
}
}
}
`);
const propsQuery = graphql(`
query VideoPage($animeSlug: String!) {
@@ -153,12 +151,12 @@ const pathsQuery = graphql(`
}
`);
export function getAnimeFromVideoPageFragment(fragment: FragmentType<typeof fragments.anime>) {
return getFragmentData(fragments.anime, fragment);
export function getAnimeFromVideoPageFragment(fragment: FragmentType<typeof VIDEO_PAGE_ANIME>) {
return getFragmentData(VIDEO_PAGE_ANIME, fragment);
}
export interface VideoPageProps extends SharedPageProps {
anime: FragmentType<typeof fragments.anime>;
anime: FragmentType<typeof VIDEO_PAGE_ANIME>;
themeIndex: number;
entryIndex: number;
videoIndex: number;
@@ -440,7 +438,7 @@ export default function VideoPage({
);
}
const buildTimeCache: Map<string, FragmentType<typeof fragments.anime>> = new Map();
const buildTimeCache: Map<string, FragmentType<typeof VIDEO_PAGE_ANIME>> = new Map();
export const getStaticProps: GetStaticProps<VideoPageProps, VideoPageParams> = async ({ params }) => {
const client = createApolloClient();
@@ -462,7 +460,7 @@ export const getStaticProps: GetStaticProps<VideoPageProps, VideoPageParams> = a
};
}
const anime = getFragmentData(fragments.anime, animeFragment);
const anime = getFragmentData(VIDEO_PAGE_ANIME, animeFragment);
if (anime) {
for (const [themeIndex, theme] of anime.animethemes.entries()) {
+46 -48
View File
@@ -34,52 +34,50 @@ const StyledList = styled.div`
text-align: center;
`;
const fragments = {
anime: graphql(`
fragment AnimeDetailPageAnime on Anime {
slug
name
season
seasonLocalized
year
synopsis
mediaFormatLocalized
animesynonyms {
text
}
series {
nodes {
slug
name
}
}
studios {
nodes {
slug
name
}
}
resources {
edges {
node {
site
siteLocalized
link
}
as
}
}
images {
nodes {
...extractImagesImage
}
}
animethemes {
...AnimeThemeFilterTheme
export const ANIME_DETAIL_PAGE_ANIME = graphql(`
fragment AnimeDetailPageAnime on Anime {
slug
name
season
seasonLocalized
year
synopsis
mediaFormatLocalized
animesynonyms {
text
}
series {
nodes {
slug
name
}
}
`),
};
studios {
nodes {
slug
name
}
}
resources {
edges {
node {
site
siteLocalized
link
}
as
}
}
images {
nodes {
...extractImagesImage
}
}
animethemes {
...AnimeThemeFilterTheme
}
}
`);
const propsQuery = graphql(`
query AnimeDetailPage($animeSlug: String!) {
@@ -101,7 +99,7 @@ const pathsQuery = graphql(`
`);
interface AnimeDetailPageProps extends SharedPageProps {
anime: FragmentType<typeof fragments.anime>;
anime: FragmentType<typeof ANIME_DETAIL_PAGE_ANIME>;
synopsisMarkdownSource: MDXRemoteSerializeResult | null;
}
@@ -110,7 +108,7 @@ interface AnimeDetailPageParams extends ParsedUrlQuery {
}
export default function AnimeDetailPage({ anime: animeFragment, synopsisMarkdownSource }: AnimeDetailPageProps) {
const anime = getFragmentData(fragments.anime, animeFragment);
const anime = getFragmentData(ANIME_DETAIL_PAGE_ANIME, animeFragment);
const [collapseSynopsis, setCollapseSynopsis] = useState(true);
const { smallCover, largeCover } = extractImages(anime.images.nodes);
@@ -210,7 +208,7 @@ export default function AnimeDetailPage({ anime: animeFragment, synopsisMarkdown
);
}
const buildTimeCache: Map<string, FragmentType<typeof fragments.anime>> = new Map();
const buildTimeCache: Map<string, FragmentType<typeof ANIME_DETAIL_PAGE_ANIME>> = new Map();
export const getStaticProps: GetStaticProps<AnimeDetailPageProps, AnimeDetailPageParams> = async ({ params }) => {
const client = createApolloClient();
@@ -232,7 +230,7 @@ export const getStaticProps: GetStaticProps<AnimeDetailPageProps, AnimeDetailPag
};
}
const anime = getFragmentData(fragments.anime, animeFragment);
const anime = getFragmentData(ANIME_DETAIL_PAGE_ANIME, animeFragment);
return {
props: {
+159 -158
View File
@@ -58,12 +58,71 @@ const StyledHeader = styled.div`
align-items: center;
`;
const fragments = {
artist: graphql(`
fragment ArtistDetailPageArtist on Artist {
...ThemeSummaryCardArtist
slug
name
export const ARTIST_DETAIL_PAGE_ARTIST = graphql(`
fragment ArtistDetailPageArtist on Artist {
...ThemeSummaryCardArtist
slug
name
performances {
alias
as
song {
id
title
performances {
artist {
__typename
... on Artist {
slug
name
}
... on Membership {
group {
slug
name
}
}
}
alias
as
}
animethemes {
...ThemeSummaryCardTheme
...ThemeSummaryCardThemeExpandable
id
type
sequence
animethemeentries {
videos {
nodes {
id
}
}
}
group {
name
slug
}
anime {
slug
name
year
season
}
song {
title
}
}
}
}
memberships {
alias
as
group {
...ThemeSummaryCardArtist
slug
name
}
performances {
alias
as
@@ -116,168 +175,107 @@ const fragments = {
}
}
}
memberships {
}
groupships {
alias
as
member {
slug
name
}
performances {
alias
as
group {
...ThemeSummaryCardArtist
slug
name
}
performances {
alias
as
song {
id
title
performances {
artist {
__typename
... on Artist {
song {
id
title
performances {
artist {
__typename
... on Artist {
slug
name
}
... on Membership {
group {
slug
name
}
... on Membership {
group {
slug
name
}
}
}
alias
as
}
animethemes {
...ThemeSummaryCardTheme
...ThemeSummaryCardThemeExpandable
id
type
sequence
animethemeentries {
videos {
nodes {
id
}
}
}
group {
name
slug
}
anime {
slug
name
year
season
}
song {
title
}
}
alias
as
}
}
}
groupships {
alias
as
member {
slug
name
}
performances {
alias
as
song {
animethemes {
...ThemeSummaryCardTheme
...ThemeSummaryCardThemeExpandable
id
title
performances {
artist {
__typename
... on Artist {
slug
name
type
sequence
animethemeentries {
videos {
nodes {
id
}
... on Membership {
group {
slug
name
}
}
}
alias
as
}
animethemes {
...ThemeSummaryCardTheme
...ThemeSummaryCardThemeExpandable
id
type
sequence
animethemeentries {
videos {
nodes {
id
}
}
}
group {
name
slug
}
anime {
slug
name
year
season
}
song {
title
}
}
group {
name
slug
}
anime {
slug
name
year
season
}
song {
title
}
}
}
}
members {
edges {
alias
as
notes
node {
...ArtistSummaryCardArtist
slug
name
}
}
}
groups {
edges {
alias
as
notes
node {
slug
name
}
}
}
images {
edges {
...extractMultipleImagesImageArtistEdge
}
}
resources {
edges {
node {
link
site
siteLocalized
}
as
}
}
}
`),
};
members {
edges {
alias
as
notes
node {
...ArtistSummaryCardArtist
slug
name
}
}
}
groups {
edges {
alias
as
notes
node {
slug
name
}
}
}
images {
edges {
...extractMultipleImagesImageArtistEdge
}
}
resources {
edges {
node {
link
site
siteLocalized
}
as
}
}
}
`);
const propsQuery = graphql(`
query ArtistDetailPage($artistSlug: String!) {
@@ -301,8 +299,8 @@ const pathsQuery = graphql(`
`);
type Performance =
| ResultOf<typeof fragments.artist>["performances"][number]
| ResultOf<typeof fragments.artist>["groupships"][number]["performances"][number];
| ResultOf<typeof ARTIST_DETAIL_PAGE_ARTIST>["performances"][number]
| ResultOf<typeof ARTIST_DETAIL_PAGE_ARTIST>["groupships"][number]["performances"][number];
function getPerformanceFilter(key: string | null): (performance: Performance) => boolean {
switch (key) {
@@ -316,7 +314,7 @@ function getPerformanceFilter(key: string | null): (performance: Performance) =>
}
interface ArtistDetailPageProps {
artist: FragmentType<typeof fragments.artist>;
artist: FragmentType<typeof ARTIST_DETAIL_PAGE_ARTIST>;
informationMarkdownSource: MDXRemoteSerializeResult | null;
}
@@ -325,7 +323,7 @@ interface ArtistDetailPageParams extends ParsedUrlQuery {
}
export default function ArtistDetailPage({ artist: artistFragment, informationMarkdownSource }: ArtistDetailPageProps) {
const artist = getFragmentData(fragments.artist, artistFragment);
const artist = getFragmentData(ARTIST_DETAIL_PAGE_ARTIST, artistFragment);
const images = extractMultipleImages(artist.images.edges);
const [collapseInformation, setCollapseInformation] = useState(true);
@@ -624,7 +622,9 @@ export default function ArtistDetailPage({ artist: artistFragment, informationMa
interface ArtistThemesProps {
themes: Performance["song"]["animethemes"];
artist: ResultOf<typeof fragments.artist> | ResultOf<typeof fragments.artist>["memberships"][number]["group"];
artist:
| ResultOf<typeof ARTIST_DETAIL_PAGE_ARTIST>
| ResultOf<typeof ARTIST_DETAIL_PAGE_ARTIST>["memberships"][number]["group"];
}
const ArtistThemes = memo(function ArtistThemes({ themes, artist }: ArtistThemesProps) {
@@ -661,7 +661,8 @@ const ArtistThemes = memo(function ArtistThemes({ themes, artist }: ArtistThemes
return <>{themeCards}</>;
});
const buildTimeCache: Map<string, FragmentType<typeof fragments.artist> & { information: string | null }> = new Map();
const buildTimeCache: Map<string, FragmentType<typeof ARTIST_DETAIL_PAGE_ARTIST> & { information: string | null }> =
new Map();
export const getStaticProps: GetStaticProps<ArtistDetailPageProps, ArtistDetailPageParams> = async ({ params }) => {
const client = createApolloClient();
+38 -39
View File
@@ -54,41 +54,40 @@ const StyledNomineeGrid = styled.div<{ style: { "--columns": number; "--rows": n
}
`;
const fragments = {
theme: graphql(`
fragment AnimeAwardsPageTheme on AnimeTheme {
...createVideoSlugTheme
id
type
sequence
anime {
slug
name
images {
nodes {
...extractImagesImage
}
}
}
song {
...SongTitleWithArtistsSong
}
}
`),
entry: graphql(`
fragment AnimeAwardPageEntry on AnimeThemeEntry {
...createVideoSlugEntry
version
videos {
export const ANIME_AWARDS_PAGE_THEME = graphql(`
fragment AnimeAwardsPageTheme on AnimeTheme {
...createVideoSlugTheme
id
type
sequence
anime {
slug
name
images {
nodes {
...createVideoSlugVideo
basename
tags
...extractImagesImage
}
}
}
`),
};
song {
...SongTitleWithArtistsSong
}
}
`);
export const ANIME_AWARD_PAGE_ENTRY = graphql(`
fragment AnimeAwardPageEntry on AnimeThemeEntry {
...createVideoSlugEntry
version
videos {
nodes {
...createVideoSlugVideo
basename
tags
}
}
}
`);
interface Nominee {
id: number;
@@ -101,8 +100,8 @@ interface HasVotes {
}
interface HasTheme {
theme: FragmentType<typeof fragments.theme>;
entry: FragmentType<typeof fragments.entry>;
theme: FragmentType<typeof ANIME_AWARDS_PAGE_THEME>;
entry: FragmentType<typeof ANIME_AWARD_PAGE_ENTRY>;
}
type Award = AwardUnvoted | AwardVoted;
@@ -171,8 +170,8 @@ function AwardSectionUnvoted({ award }: AwardSectionUnvotedProps) {
const [typeFilter, setTypeFilter] = useState<string | null>(null);
const sortFn: Comparator<HasTheme> = (a, b) => {
const nameA = getFragmentData(fragments.theme, a.theme)?.anime?.name;
const nameB = getFragmentData(fragments.theme, b.theme)?.anime?.name;
const nameA = getFragmentData(ANIME_AWARDS_PAGE_THEME, a.theme)?.anime?.name;
const nameB = getFragmentData(ANIME_AWARDS_PAGE_THEME, b.theme)?.anime?.name;
return (nameA && nameB && nameA.localeCompare(nameB)) || 0;
};
@@ -295,8 +294,8 @@ const StyledRank = styled(Text)`
`;
interface AwardThemeSummaryCardProps extends ComponentPropsWithoutRef<typeof StyledSummaryCardWrapper> {
theme: FragmentType<typeof fragments.theme>;
entry: FragmentType<typeof fragments.entry>;
theme: FragmentType<typeof ANIME_AWARDS_PAGE_THEME>;
entry: FragmentType<typeof ANIME_AWARD_PAGE_ENTRY>;
rank?: number;
votes?: number | null;
}
@@ -308,8 +307,8 @@ function AwardThemeSummaryCard({
votes,
...props
}: AwardThemeSummaryCardProps) {
const theme = getFragmentData(fragments.theme, themeFragment);
const entry = getFragmentData(fragments.entry, entryFragment);
const theme = getFragmentData(ANIME_AWARDS_PAGE_THEME, themeFragment);
const entry = getFragmentData(ANIME_AWARD_PAGE_ENTRY, entryFragment);
if (!theme?.anime) {
return null;
+17 -18
View File
@@ -65,31 +65,30 @@ const Grid = styled.div<{ $columns: number }>`
}
`;
const fragments = {
featuredTheme: graphql(`
fragment HomePageFeaturedTheme on FeaturedTheme {
animethemeentry {
...FeaturedThemeEntry
}
video {
...FeaturedThemeVideo
}
export const HOME_PAGE_FEATURED_THEME = graphql(`
fragment HomePageFeaturedTheme on FeaturedTheme {
animethemeentry {
...FeaturedThemeEntry
}
`),
announcement: graphql(`
fragment HomePageAnnouncement on Announcement {
content
video {
...FeaturedThemeVideo
}
`),
};
}
`);
export const HOME_PAGE_ANNOUNCEMENT = graphql(`
fragment HomePageAnnouncement on Announcement {
content
}
`);
interface HomePageProps {
featuredTheme: FragmentType<typeof fragments.featuredTheme> | null;
featuredTheme: FragmentType<typeof HOME_PAGE_FEATURED_THEME> | null;
announcementSources: MDXRemoteSerializeResult[];
}
export default function HomePage({ featuredTheme: featuredThemeFragment, announcementSources }: HomePageProps) {
const featuredTheme = getFragmentData(fragments.featuredTheme, featuredThemeFragment);
const featuredTheme = getFragmentData(HOME_PAGE_FEATURED_THEME, featuredThemeFragment);
const { me } = useAuth();
const { currentYear, currentSeason } = useCurrentSeason();
@@ -259,7 +258,7 @@ export const getStaticProps: GetStaticProps<HomePageProps> = async () => {
`),
});
const announcements = getFragmentData(fragments.announcement, data.announcementPagination.data);
const announcements = getFragmentData(HOME_PAGE_ANNOUNCEMENT, data.announcementPagination.data);
return {
props: {
+62 -60
View File
@@ -128,7 +128,7 @@ const comparators = {
[ANIME_NEW_OLD]: sortTransformed(getComparator(ANIME_NEW_OLD), (track) => track.animethemeentry.animetheme?.anime),
[RANK_ASC]: (a, b) => a.rank - b.rank,
[RANK_DESC]: (a, b) => a.rank - b.rank,
} satisfies Record<string, Comparator<ResultOf<typeof fragments.track> & { rank: number }>>;
} satisfies Record<string, Comparator<ResultOf<typeof PLAYLIST_DETAIL_PAGE_TRACK> & { rank: number }>>;
type LinkedList<T> = Array<
{
@@ -163,60 +163,60 @@ function sortLinkedList<T>(list: LinkedList<T>) {
return sortedList;
}
const fragments = {
playlist: graphql(`
fragment PlaylistDetailPagePlaylist on Playlist {
...PlaylistEditDialogPlaylist
...PlaylistTrackRemoveDialogPlaylist
id
export const PLAYLIST_DETAIL_PAGE_PLAYLIST = graphql(`
fragment PlaylistDetailPagePlaylist on Playlist {
...PlaylistEditDialogPlaylist
...PlaylistTrackRemoveDialogPlaylist
id
name
description
visibility
tracksCount
user {
name
description
visibility
tracksCount
user {
name
}
}
`),
track: graphql(`
fragment PlaylistDetailPageTrack on PlaylistTrack {
}
`);
export const PLAYLIST_DETAIL_PAGE_TRACK = graphql(`
fragment PlaylistDetailPageTrack on PlaylistTrack {
id
video {
...VideoSummaryCardVideo
...FeaturedThemeVideo
...PlaylistTrackAddDialogVideo
...PlaylistTrackRemoveDialogVideo
id
video {
...VideoSummaryCardVideo
...FeaturedThemeVideo
...PlaylistTrackAddDialogVideo
...PlaylistTrackRemoveDialogVideo
id
}
animethemeentry {
...VideoSummaryCardEntry
...FeaturedThemeEntry
...PlaylistTrackAddDialogEntry
...PlaylistTrackRemoveDialogEntry
animetheme {
anime {
name
year
season
images {
nodes {
...extractImagesImage
}
}
animethemeentry {
...VideoSummaryCardEntry
...FeaturedThemeEntry
...PlaylistTrackAddDialogEntry
...PlaylistTrackRemoveDialogEntry
animetheme {
anime {
name
year
season
images {
nodes {
...extractImagesImage
}
}
song {
title
}
}
song {
title
}
}
}
`),
me: graphql(`
fragment PlaylistDetailPageMe on Me {
name
}
`),
};
}
`);
export const PLAYLIST_DETAIL_PAGE_ME = graphql(`
fragment PlaylistDetailPageMe on Me {
name
}
`);
export const PLAYLIST_DETAIL_PAGE_PLAYLIST = graphql(`
query PlaylistDetailPagePlaylist($playlistId: String!) {
@@ -244,9 +244,9 @@ const meQuery = graphql(`
`);
interface PlaylistDetailPageProps extends SharedPageProps {
playlist: FragmentType<typeof fragments.playlist>;
tracks: Array<FragmentType<typeof fragments.track>>;
me: FragmentType<typeof fragments.me> | null;
playlist: FragmentType<typeof PLAYLIST_DETAIL_PAGE_PLAYLIST>;
tracks: Array<FragmentType<typeof PLAYLIST_DETAIL_PAGE_TRACK>>;
me: FragmentType<typeof PLAYLIST_DETAIL_PAGE_ME> | null;
}
interface PlaylistDetailPageParams extends ParsedUrlQuery {
@@ -258,7 +258,7 @@ export default function PlaylistDetailPage({
tracks: tracksFragment,
me: meFragment,
}: PlaylistDetailPageProps) {
const initialPlaylist = getFragmentData(fragments.playlist, playlistFragment);
const initialPlaylist = getFragmentData(PLAYLIST_DETAIL_PAGE_PLAYLIST, playlistFragment);
const { setWatchList, setWatchListFactory, setCurrentWatchListItem } = useContext(PlayerContext);
const router = useRouter();
@@ -268,9 +268,11 @@ export default function PlaylistDetailPage({
});
const { data: meData } = useQuery(meQuery);
const playlist = getFragmentData(fragments.playlist, playlistData?.playlist ?? playlistFragment);
const tracks = sortLinkedList(getFragmentData(fragments.track, playlistData?.playlist.tracks ?? tracksFragment));
const me = getFragmentData(fragments.me, meData?.me ?? meFragment);
const playlist = getFragmentData(PLAYLIST_DETAIL_PAGE_PLAYLIST, playlistData?.playlist ?? playlistFragment);
const tracks = sortLinkedList(
getFragmentData(PLAYLIST_DETAIL_PAGE_TRACK, playlistData?.playlist.tracks ?? tracksFragment),
);
const me = getFragmentData(PLAYLIST_DETAIL_PAGE_ME, meData?.me ?? meFragment);
if (!playlist) {
location.reload();
@@ -465,7 +467,7 @@ export default function PlaylistDetailPage({
}
interface DescriptionProps {
playlist: ResultOf<typeof fragments.playlist>;
playlist: ResultOf<typeof PLAYLIST_DETAIL_PAGE_PLAYLIST>;
description: string;
setDescription: (newValue: string) => void;
isEditable: boolean;
@@ -566,14 +568,14 @@ function Description({ playlist, description, setDescription, isEditable, setEdi
}
interface PlaylistTrackListProps {
playlist: ResultOf<typeof fragments.playlist>;
tracks: Array<ResultOf<typeof fragments.track> & { rank: number }>;
playlist: ResultOf<typeof PLAYLIST_DETAIL_PAGE_PLAYLIST>;
tracks: Array<ResultOf<typeof PLAYLIST_DETAIL_PAGE_TRACK> & { rank: number }>;
isReorderable: boolean;
isOwner: boolean;
isRanking: boolean;
playAll: (index: number) => void;
updateTrackOrderRemote: (trackId: string) => void;
updateTrackOrder: (tracks: Array<ResultOf<typeof fragments.track> & { rank: number }>) => void;
updateTrackOrder: (tracks: Array<ResultOf<typeof PLAYLIST_DETAIL_PAGE_TRACK> & { rank: number }>) => void;
}
const PlaylistTrackList = memo(function PlaylistTrackList({
@@ -632,8 +634,8 @@ const StyledDragHandle = styled(Icon)`
`;
interface PlaylistTrackProps {
playlist: ResultOf<typeof fragments.playlist>;
track: ResultOf<typeof fragments.track> & { rank: number };
playlist: ResultOf<typeof PLAYLIST_DETAIL_PAGE_PLAYLIST>;
track: ResultOf<typeof PLAYLIST_DETAIL_PAGE_TRACK> & { rank: number };
isOwner: boolean;
isRanking: boolean;
isDraggable?: boolean;
+22 -24
View File
@@ -135,30 +135,28 @@ const StyledRoleBadge = styled.span<{ $color: string }>`
letter-spacing: 1px;
`;
const fragments = {
me: graphql(`
fragment ProfilePageMe on Me {
...ProfileImageUser
name
email
emailVerifiedAt
createdAt
roles {
nodes {
name
color
priority
default
}
}
playlists(sort: [CREATED_AT_DESC]) {
...PlaylistSummaryCardPlaylist
...PlaylistRemoveDialogPlaylist
id
export const PROFILE_PAGE_ME = graphql(`
fragment ProfilePageMe on Me {
...ProfileImageUser
name
email
emailVerifiedAt
createdAt
roles {
nodes {
name
color
priority
default
}
}
`),
};
playlists(sort: [CREATED_AT_DESC]) {
...PlaylistSummaryCardPlaylist
...PlaylistRemoveDialogPlaylist
id
}
}
`);
export const PROFILE_PAGE = graphql(`
query ProfilePage {
@@ -169,13 +167,13 @@ export const PROFILE_PAGE = graphql(`
`);
interface ProfilePageProps extends SharedPageProps {
me: FragmentType<typeof fragments.me> | null;
me: FragmentType<typeof PROFILE_PAGE_ME> | null;
}
export default function ProfilePage({ me: meFragment }: ProfilePageProps) {
const { data } = useQuery(PROFILE_PAGE);
const me = getFragmentData(fragments.me, data?.me ?? meFragment);
const me = getFragmentData(PROFILE_PAGE_ME, data?.me ?? meFragment);
const { history, clearHistory } = useWatchHistory();
+30 -32
View File
@@ -31,41 +31,39 @@ const StyledDesktopOnly = styled.div`
}
`;
const fragments = {
series: graphql(`
fragment SeriesDetailPageSeries on Series {
slug
name
anime {
nodes {
...AnimeSummaryCardAnime
...AnimeSummaryCardAnimeExpandable
name
slug
year
season
animethemes {
type
sequence
animethemeentries {
version
videos {
nodes {
tags
}
export const SERIES_DETAIL_PAGE_SERIES = graphql(`
fragment SeriesDetailPageSeries on Series {
slug
name
anime {
nodes {
...AnimeSummaryCardAnime
...AnimeSummaryCardAnimeExpandable
name
slug
year
season
animethemes {
type
sequence
animethemeentries {
version
videos {
nodes {
tags
}
}
}
images {
nodes {
...extractImagesImage
}
}
images {
nodes {
...extractImagesImage
}
}
}
}
`),
};
}
`);
const propsQuery = graphql(`
query SeriesDetailPage($seriesSlug: String!) {
@@ -87,7 +85,7 @@ const pathsQuery = graphql(`
`);
interface SeriesDetailPageProps {
series: FragmentType<typeof fragments.series>;
series: FragmentType<typeof SERIES_DETAIL_PAGE_SERIES>;
}
interface SeriesDetailPageParams extends ParsedUrlQuery {
@@ -95,7 +93,7 @@ interface SeriesDetailPageParams extends ParsedUrlQuery {
}
export default function SeriesDetailPage({ series: seriesFragment }: SeriesDetailPageProps) {
const series = getFragmentData(fragments.series, seriesFragment);
const series = getFragmentData(SERIES_DETAIL_PAGE_SERIES, seriesFragment);
const anime = series.anime.nodes;
const [showFilter, toggleShowFilter] = useToggle();
@@ -141,7 +139,7 @@ export default function SeriesDetailPage({ series: seriesFragment }: SeriesDetai
}
interface SeriesAnimeProps {
anime: ResultOf<typeof fragments.series>["anime"]["nodes"];
anime: ResultOf<typeof SERIES_DETAIL_PAGE_SERIES>["anime"]["nodes"];
}
const SeriesAnime = memo(function SeriesAnime({ anime }: SeriesAnimeProps) {
@@ -150,7 +148,7 @@ const SeriesAnime = memo(function SeriesAnime({ anime }: SeriesAnimeProps) {
return <>{animeCards}</>;
});
const buildTimeCache: Map<string, FragmentType<typeof fragments.series>> = new Map();
const buildTimeCache: Map<string, FragmentType<typeof SERIES_DETAIL_PAGE_SERIES>> = new Map();
export const getStaticProps: GetStaticProps<SeriesDetailPageProps, SeriesDetailPageParams> = async ({ params }) => {
const client = createApolloClient();
+45 -47
View File
@@ -40,58 +40,56 @@ const StyledList = styled.div`
text-align: center;
`;
const fragments = {
studio: graphql(`
fragment StudioDetailPageStudio on Studio {
...StudioCoverImageStudio
slug
name
anime {
nodes {
...AnimeSummaryCardAnime
...AnimeSummaryCardAnimeExpandable
name
slug
year
season
animethemes {
type
sequence
animethemeentries {
version
videos {
nodes {
tags
}
export const STUDIO_DETAIL_PAGE_STUDIO = graphql(`
fragment StudioDetailPageStudio on Studio {
...StudioCoverImageStudio
slug
name
anime {
nodes {
...AnimeSummaryCardAnime
...AnimeSummaryCardAnimeExpandable
name
slug
year
season
animethemes {
type
sequence
animethemeentries {
version
videos {
nodes {
tags
}
}
}
images {
nodes {
facet
link
}
}
}
}
resources {
edges {
as
node {
images {
nodes {
facet
link
site
siteLocalized
}
}
}
images {
nodes {
...extractImagesImage
}
}
}
`),
};
resources {
edges {
as
node {
link
site
siteLocalized
}
}
}
images {
nodes {
...extractImagesImage
}
}
}
`);
const propsQuery = graphql(`
query StudioDetailPage($studioSlug: String!) {
@@ -113,7 +111,7 @@ const pathsQuery = graphql(`
`);
interface StudioDetailPageProps {
studio: FragmentType<typeof fragments.studio>;
studio: FragmentType<typeof STUDIO_DETAIL_PAGE_STUDIO>;
}
interface StudioDetailPageParams extends ParsedUrlQuery {
@@ -121,7 +119,7 @@ interface StudioDetailPageParams extends ParsedUrlQuery {
}
export default function StudioDetailPage({ studio: studioFragment }: StudioDetailPageProps) {
const studio = getFragmentData(fragments.studio, studioFragment);
const studio = getFragmentData(STUDIO_DETAIL_PAGE_STUDIO, studioFragment);
const anime = studio.anime.nodes;
const { largeCover } = extractImages(studio.images.nodes);
@@ -186,7 +184,7 @@ export default function StudioDetailPage({ studio: studioFragment }: StudioDetai
}
interface StudioAnimeProps {
anime: ResultOf<typeof fragments.studio>["anime"]["nodes"];
anime: ResultOf<typeof STUDIO_DETAIL_PAGE_STUDIO>["anime"]["nodes"];
}
const StudioAnime = memo(function StudioAnime({ anime }: StudioAnimeProps) {
@@ -195,7 +193,7 @@ const StudioAnime = memo(function StudioAnime({ anime }: StudioAnimeProps) {
return <>{animeCards}</>;
});
const buildTimeCache: Map<string, FragmentType<typeof fragments.studio>> = new Map();
const buildTimeCache: Map<string, FragmentType<typeof STUDIO_DETAIL_PAGE_STUDIO>> = new Map();
export const getStaticProps: GetStaticProps<StudioDetailPageProps, StudioDetailPageParams> = async ({ params }) => {
const client = createApolloClient();
+24 -25
View File
@@ -15,29 +15,28 @@ import fetchStaticPaths from "@/utils/fetchStaticPaths";
import type { SharedPageProps } from "@/utils/getSharedPageProps";
import getSharedPageProps from "@/utils/getSharedPageProps";
const fragments = {
year: graphql(`
fragment SeasonDetailPageYear on AnimeYear {
...SeasonNavigationYear
year
}
`),
season: graphql(`
fragment SeasonDetailPageSeason on AnimeYearSeason {
...SeasonNavigationSeason
season
seasonLocalized
anime {
data {
...AnimeSummaryCardAnime
...AnimeSummaryCardAnimeExpandable
slug
name
}
export const SEASON_DETAIL_PAGE_YEAR = graphql(`
fragment SeasonDetailPageYear on AnimeYear {
...SeasonNavigationYear
year
}
`);
export const SEASON_DETAIL_PAGE_SEASON = graphql(`
fragment SeasonDetailPageSeason on AnimeYearSeason {
...SeasonNavigationSeason
season
seasonLocalized
anime {
data {
...AnimeSummaryCardAnime
...AnimeSummaryCardAnimeExpandable
slug
name
}
}
`),
};
}
`);
const pathsQuery = graphql(`
query SeasonDetailPageAll {
@@ -72,8 +71,8 @@ const propsQuery = graphql(`
export interface SeasonDetailPageProps extends SharedPageProps {
isYearOrSeasonPage: true;
year: FragmentType<typeof fragments.year>;
season: FragmentType<typeof fragments.season>;
year: FragmentType<typeof SEASON_DETAIL_PAGE_YEAR>;
season: FragmentType<typeof SEASON_DETAIL_PAGE_SEASON>;
years: ResultOf<typeof propsQuery>["animeyears"];
}
@@ -83,8 +82,8 @@ interface SeasonDetailPageParams extends ParsedUrlQuery {
}
export default function SeasonDetailPage({ year: yearFragment, season: seasonFragment }: SeasonDetailPageProps) {
const year = getFragmentData(fragments.year, yearFragment);
const season = getFragmentData(fragments.season, seasonFragment);
const year = getFragmentData(SEASON_DETAIL_PAGE_YEAR, yearFragment);
const season = getFragmentData(SEASON_DETAIL_PAGE_SEASON, seasonFragment);
const animeList = season.anime.data.filter((anime) => anime.name).sort((a, b) => a.name.localeCompare(b.name));
return (
+9 -11
View File
@@ -70,24 +70,22 @@ export default function YearDetailPage({ year }: YearDetailPageProps) {
);
}
const fragments = {
anime: graphql(`
fragment SeasonPreviewAnime on Anime {
...AnimeSummaryCardAnime
...AnimeSummaryCardAnimeExpandable
slug
}
`),
};
export const SEASON_PREVIEW_ANIME = graphql(`
fragment SeasonPreviewAnime on Anime {
...AnimeSummaryCardAnime
...AnimeSummaryCardAnimeExpandable
slug
}
`);
interface SeasonPreviewProps {
season: string;
year: number;
animes: Array<FragmentType<typeof fragments.anime>>;
animes: Array<FragmentType<typeof SEASON_PREVIEW_ANIME>>;
}
function SeasonPreview({ season, year, animes: animesFragment }: SeasonPreviewProps) {
const animes = getFragmentData(fragments.anime, animesFragment);
const animes = getFragmentData(SEASON_PREVIEW_ANIME, animesFragment);
return (
<>
+26 -26
View File
@@ -2,27 +2,27 @@ import type { WatchListItem } from "@/context/playerContext";
import { type FragmentType, getFragmentData, graphql } from "@/graphql/generated";
import { getAnimeFromVideoPageFragment, type VideoPageProps } from "@/pages/anime/[animeSlug]/[videoSlug]";
const fragments = {
theme: graphql(`
fragment createVideoSlugTheme on AnimeTheme {
type
sequence
group {
slug
}
export const CREATE_VIDEO_SLUG_THEME = graphql(`
fragment createVideoSlugTheme on AnimeTheme {
type
sequence
group {
slug
}
`),
entry: graphql(`
fragment createVideoSlugEntry on AnimeThemeEntry {
version
}
`),
video: graphql(`
fragment createVideoSlugVideo on Video {
tags
}
`),
};
}
`);
export const CREATE_VIDEO_SLUG_ENTRY = graphql(`
fragment createVideoSlugEntry on AnimeThemeEntry {
version
}
`);
export const CREATE_VIDEO_SLUG_VIDEO = graphql(`
fragment createVideoSlugVideo on Video {
tags
}
`);
/**
* Slug format is:
@@ -30,13 +30,13 @@ const fragments = {
* `<OP|ED><#>[v#][-<Group>][-<Tags>]`
*/
const createVideoSlug = (
themeFragment: FragmentType<typeof fragments.theme>,
entryFragment: FragmentType<typeof fragments.entry>,
videoFragment: FragmentType<typeof fragments.video>,
themeFragment: FragmentType<typeof CREATE_VIDEO_SLUG_THEME>,
entryFragment: FragmentType<typeof CREATE_VIDEO_SLUG_ENTRY>,
videoFragment: FragmentType<typeof CREATE_VIDEO_SLUG_VIDEO>,
) => {
const theme = getFragmentData(fragments.theme, themeFragment);
const entry = getFragmentData(fragments.entry, entryFragment);
const video = getFragmentData(fragments.video, videoFragment);
const theme = getFragmentData(CREATE_VIDEO_SLUG_THEME, themeFragment);
const entry = getFragmentData(CREATE_VIDEO_SLUG_ENTRY, entryFragment);
const video = getFragmentData(CREATE_VIDEO_SLUG_VIDEO, videoFragment);
let slug = theme.type + (theme.sequence || 1);
+8 -10
View File
@@ -1,13 +1,11 @@
import { type FragmentType, getFragmentData, graphql } from "@/graphql/generated";
const fragments = {
image: graphql(`
fragment extractImagesImage on Image {
link
facet
}
`),
};
export const EXTRACT_IMAGES_IMAGE = graphql(`
fragment extractImagesImage on Image {
link
facet
}
`);
interface ExtractImagesResult {
smallCover?: string;
@@ -15,9 +13,9 @@ interface ExtractImagesResult {
}
export default function extractImages(
imageFragments: Array<FragmentType<typeof fragments.image>> | null,
imageFragments: Array<FragmentType<typeof EXTRACT_IMAGES_IMAGE>> | null,
): ExtractImagesResult {
const images = imageFragments ? getFragmentData(fragments.image, imageFragments) : [];
const images = imageFragments ? getFragmentData(EXTRACT_IMAGES_IMAGE, imageFragments) : [];
const extractedImages: ExtractImagesResult = {};
for (const image of images) {
+12 -12
View File
@@ -1,16 +1,14 @@
import { type FragmentType, getFragmentData, graphql } from "@/graphql/generated";
const fragments = {
imageEdge: graphql(`
fragment extractMultipleImagesImageArtistEdge on ArtistImageEdge {
depth
node {
link
facet
}
export const EXTRACT_MULTIPLE_IMAGES_IMAGE_ARTIST_EDGE = graphql(`
fragment extractMultipleImagesImageArtistEdge on ArtistImageEdge {
depth
node {
link
facet
}
`),
};
}
`);
interface ExtractMultipleImagesResult {
link: string;
@@ -19,9 +17,11 @@ interface ExtractMultipleImagesResult {
}
export default function extractMultipleImages(
imageEdgeFragments: Array<FragmentType<typeof fragments.imageEdge>> | null,
imageEdgeFragments: Array<FragmentType<typeof EXTRACT_MULTIPLE_IMAGES_IMAGE_ARTIST_EDGE>> | null,
): Array<ExtractMultipleImagesResult> {
const imageEdges = imageEdgeFragments ? getFragmentData(fragments.imageEdge, imageEdgeFragments) : [];
const imageEdges = imageEdgeFragments
? getFragmentData(EXTRACT_MULTIPLE_IMAGES_IMAGE_ARTIST_EDGE, imageEdgeFragments)
: [];
if (imageEdges?.length > 0) {
const largeCovers = imageEdges.filter((edge) => edge.node.facet === "LARGE_COVER");