diff --git a/src/lib/components/ui/profile/Profile.svelte b/src/lib/components/ui/profile/Profile.svelte
new file mode 100644
index 0000000..12cdaa2
--- /dev/null
+++ b/src/lib/components/ui/profile/Profile.svelte
@@ -0,0 +1,107 @@
+
+
+{#if user}
+ {@const name = user.name}
+ {@const avatar = user.avatar?.medium ?? ''}
+ {@const banner = user.bannerImage ?? ''}
+ {@const bubble = user.donatorBadge}
+
+
+
+
+
+ {name}
+
+
+
+
+
+ {#if banner}
+

+ {/if}
+
+
+ {name}
+
+
+
+
+ {#if user.isFollower}
+ Follows you
+ {/if}
+ Joined {since(new Date((user.createdAt ?? 0) * 1000))}
+
+
+ {#if bubble && bubble !== 'Donator'}
+
+ {/if}
+
+
+
+ {user.statistics?.anime?.count ?? 0} anime
+ {user.statistics?.anime?.episodesWatched ?? 0} episodes
+ {since(new Date(Date.now() - (user.statistics?.anime?.minutesWatched ?? 0) * 60 * 1000)).replace('ago', 'watched')}
+
+
+
+
+
+{/if}
+
+
diff --git a/src/lib/components/ui/profile/index.ts b/src/lib/components/ui/profile/index.ts
new file mode 100644
index 0000000..0eec956
--- /dev/null
+++ b/src/lib/components/ui/profile/index.ts
@@ -0,0 +1 @@
+export { default as Profile } from './Profile.svelte'
diff --git a/src/lib/modules/anilist/client.ts b/src/lib/modules/anilist/client.ts
index f789ca2..38bfe76 100644
--- a/src/lib/modules/anilist/client.ts
+++ b/src/lib/modules/anilist/client.ts
@@ -219,7 +219,8 @@ class AnilistClient {
AiringSchedule: () => null,
MediaListCollection: e => (e.user as {id: string | null}).id,
MediaListGroup: () => null,
- UserAvatar: () => null
+ UserAvatar: () => null,
+ UserOptions: () => null
}
}),
authExchange(async utils => {
diff --git a/src/lib/modules/anilist/graphql-turbo.d.ts b/src/lib/modules/anilist/graphql-turbo.d.ts
index a2e657c..272c14a 100644
--- a/src/lib/modules/anilist/graphql-turbo.d.ts
+++ b/src/lib/modules/anilist/graphql-turbo.d.ts
@@ -24,30 +24,30 @@ declare module 'gql.tada' {
TadaDocumentNode<{ id: number; title: { userPreferred: string | null; } | null; mediaListEntry: { status: "CURRENT" | "PLANNING" | "COMPLETED" | "DROPPED" | "PAUSED" | "REPEATING" | null; } | null; aired: { n: ({ a: number; e: number; } | null)[] | null; } | null; notaired: { n: ({ a: number; e: number; } | null)[] | null; } | null; }, {}, { fragment: "ScheduleMedia"; on: "Media"; masked: false; }>;
"\n query Schedule($seasonCurrent: MediaSeason, $seasonYearCurrent: Int, $seasonLast: MediaSeason, $seasonYearLast: Int, $seasonNext: MediaSeason, $seasonYearNext: Int, $ids: [Int]) {\n curr1: Page(page: 1) {\n media(type: ANIME, season: $seasonCurrent, seasonYear: $seasonYearCurrent, countryOfOrigin: JP, format_not: TV_SHORT, onList: true, id_in: $ids) {\n ...ScheduleMedia\n }\n }\n curr2: Page(page: 2) {\n media(type: ANIME, season: $seasonCurrent, seasonYear: $seasonYearCurrent, countryOfOrigin: JP, format_not: TV_SHORT, onList: true, id_in: $ids) {\n ...ScheduleMedia\n }\n }\n curr3: Page(page: 3) {\n media(type: ANIME, season: $seasonCurrent, seasonYear: $seasonYearCurrent, countryOfOrigin: JP, format_not: TV_SHORT, onList: true, id_in: $ids) {\n ...ScheduleMedia\n }\n }\n residue: Page(page: 1) {\n media(type: ANIME, season: $seasonLast, seasonYear: $seasonYearLast, episodes_greater: 16, countryOfOrigin: JP, format_not: TV_SHORT, onList: true, id_in: $ids) {\n ...ScheduleMedia\n }\n },\n next1: Page(page: 1) {\n media(type: ANIME, season: $seasonNext, seasonYear: $seasonYearNext, sort: [START_DATE], countryOfOrigin: JP, format_not: TV_SHORT, onList: true, id_in: $ids) {\n ...ScheduleMedia\n }\n },\n next2: Page(page: 2) {\n media(type: ANIME, season: $seasonNext, seasonYear: $seasonYearNext, sort: [START_DATE], countryOfOrigin: JP, format_not: TV_SHORT, onList: true, id_in: $ids) {\n ...ScheduleMedia\n }\n }\n }\n":
TadaDocumentNode<{ curr1: { media: ({ id: number; title: { userPreferred: string | null; } | null; mediaListEntry: { status: "CURRENT" | "PLANNING" | "COMPLETED" | "DROPPED" | "PAUSED" | "REPEATING" | null; } | null; aired: { n: ({ a: number; e: number; } | null)[] | null; } | null; notaired: { n: ({ a: number; e: number; } | null)[] | null; } | null; } | null)[] | null; } | null; curr2: { media: ({ id: number; title: { userPreferred: string | null; } | null; mediaListEntry: { status: "CURRENT" | "PLANNING" | "COMPLETED" | "DROPPED" | "PAUSED" | "REPEATING" | null; } | null; aired: { n: ({ a: number; e: number; } | null)[] | null; } | null; notaired: { n: ({ a: number; e: number; } | null)[] | null; } | null; } | null)[] | null; } | null; curr3: { media: ({ id: number; title: { userPreferred: string | null; } | null; mediaListEntry: { status: "CURRENT" | "PLANNING" | "COMPLETED" | "DROPPED" | "PAUSED" | "REPEATING" | null; } | null; aired: { n: ({ a: number; e: number; } | null)[] | null; } | null; notaired: { n: ({ a: number; e: number; } | null)[] | null; } | null; } | null)[] | null; } | null; residue: { media: ({ id: number; title: { userPreferred: string | null; } | null; mediaListEntry: { status: "CURRENT" | "PLANNING" | "COMPLETED" | "DROPPED" | "PAUSED" | "REPEATING" | null; } | null; aired: { n: ({ a: number; e: number; } | null)[] | null; } | null; notaired: { n: ({ a: number; e: number; } | null)[] | null; } | null; } | null)[] | null; } | null; next1: { media: ({ id: number; title: { userPreferred: string | null; } | null; mediaListEntry: { status: "CURRENT" | "PLANNING" | "COMPLETED" | "DROPPED" | "PAUSED" | "REPEATING" | null; } | null; aired: { n: ({ a: number; e: number; } | null)[] | null; } | null; notaired: { n: ({ a: number; e: number; } | null)[] | null; } | null; } | null)[] | null; } | null; next2: { media: ({ id: number; title: { userPreferred: string | null; } | null; mediaListEntry: { status: "CURRENT" | "PLANNING" | "COMPLETED" | "DROPPED" | "PAUSED" | "REPEATING" | null; } | null; aired: { n: ({ a: number; e: number; } | null)[] | null; } | null; notaired: { n: ({ a: number; e: number; } | null)[] | null; } | null; } | null)[] | null; } | null; }, { ids?: (number | null)[] | null | undefined; seasonYearNext?: number | null | undefined; seasonNext?: "WINTER" | "SPRING" | "SUMMER" | "FALL" | null | undefined; seasonYearLast?: number | null | undefined; seasonLast?: "WINTER" | "SPRING" | "SUMMER" | "FALL" | null | undefined; seasonYearCurrent?: number | null | undefined; seasonCurrent?: "WINTER" | "SPRING" | "SUMMER" | "FALL" | null | undefined; }, void>;
- "\n query Following($id: Int!) {\n Page {\n mediaList(mediaId: $id, isFollowing: true, sort: UPDATED_TIME_DESC) {\n id,\n status,\n score,\n progress,\n user {\n id,\n name,\n avatar {\n medium\n }\n }\n }\n }\n }\n":
- TadaDocumentNode<{ Page: { mediaList: ({ id: number; status: "CURRENT" | "PLANNING" | "COMPLETED" | "DROPPED" | "PAUSED" | "REPEATING" | null; score: number | null; progress: number | null; user: { id: number; name: string; avatar: { medium: string | null; } | null; } | null; } | null)[] | null; } | null; }, { id: number; }, void>;
- "\n mutation Entry($lists: [String], $id: Int!, $status: MediaListStatus, $progress: Int, $repeat: Int, $score: Int) {\n SaveMediaListEntry(mediaId: $id, status: $status, progress: $progress, repeat: $repeat, scoreRaw: $score, customLists: $lists) {\n id,\n media {\n id,\n status,\n mediaListEntry {\n ...FullMediaList\n },\n nextAiringEpisode {\n episode\n }\n }\n }\n }\n":
- TadaDocumentNode<{ SaveMediaListEntry: { id: number; media: { id: number; status: "FINISHED" | "RELEASING" | "NOT_YET_RELEASED" | "CANCELLED" | "HIATUS" | null; mediaListEntry: { id: number; status: "CURRENT" | "PLANNING" | "COMPLETED" | "DROPPED" | "PAUSED" | "REPEATING" | null; progress: number | null; repeat: number | null; score: number | null; customLists: unknown; } | null; nextAiringEpisode: { episode: number; } | null; } | null; } | null; }, { score?: number | null | undefined; repeat?: number | null | undefined; progress?: number | null | undefined; status?: "CURRENT" | "PLANNING" | "COMPLETED" | "DROPPED" | "PAUSED" | "REPEATING" | null | undefined; id: number; lists?: (string | null)[] | null | undefined; }, void>;
+ "\n fragment UserFrag on User @_unmask {\n id,\n bannerImage,\n about,\n isFollowing,\n isFollower,\n donatorBadge,\n options {\n profileColor\n },\n createdAt,\n name,\n avatar {\n medium\n },\n statistics {\n anime {\n count,\n minutesWatched,\n episodesWatched,\n genres(limit: 3, sort: COUNT_DESC) {\n genre,\n count\n }\n }\n }\n }\n":
+ TadaDocumentNode<{ id: number; bannerImage: string | null; about: string | null; isFollowing: boolean | null; isFollower: boolean | null; donatorBadge: string | null; options: { profileColor: string | null; } | null; createdAt: number | null; name: string; avatar: { medium: string | null; } | null; statistics: { anime: { count: number; minutesWatched: number; episodesWatched: number; genres: ({ genre: string | null; count: number; } | null)[] | null; } | null; } | null; }, {}, { fragment: "UserFrag"; on: "User"; masked: false; }>;
+ "\n query Following($id: Int!) {\n Page {\n mediaList(mediaId: $id, isFollowing: true, sort: UPDATED_TIME_DESC) {\n id,\n status,\n score,\n progress,\n user {\n ...UserFrag\n }\n }\n }\n }\n":
+ TadaDocumentNode<{ Page: { mediaList: ({ id: number; status: "CURRENT" | "PLANNING" | "COMPLETED" | "DROPPED" | "PAUSED" | "REPEATING" | null; score: number | null; progress: number | null; user: { id: number; bannerImage: string | null; about: string | null; isFollowing: boolean | null; isFollower: boolean | null; donatorBadge: string | null; options: { profileColor: string | null; } | null; createdAt: number | null; name: string; avatar: { medium: string | null; } | null; statistics: { anime: { count: number; minutesWatched: number; episodesWatched: number; genres: ({ genre: string | null; count: number; } | null)[] | null; } | null; } | null; } | null; } | null)[] | null; } | null; }, { id: number; }, void>;
+ "\n mutation Entry($lists: [String], $id: Int!, $status: MediaListStatus, $progress: Int, $repeat: Int, $score: Int) {\n SaveMediaListEntry(mediaId: $id, status: $status, progress: $progress, repeat: $repeat, scoreRaw: $score, customLists: $lists) {\n id,\n ...FullMediaList,\n media {\n id\n }\n }\n }\n":
+ TadaDocumentNode<{ SaveMediaListEntry: { id: number; status: "CURRENT" | "PLANNING" | "COMPLETED" | "DROPPED" | "PAUSED" | "REPEATING" | null; progress: number | null; repeat: number | null; score: number | null; customLists: unknown; media: { id: number; } | null; } | null; }, { score?: number | null | undefined; repeat?: number | null | undefined; progress?: number | null | undefined; status?: "CURRENT" | "PLANNING" | "COMPLETED" | "DROPPED" | "PAUSED" | "REPEATING" | null | undefined; id: number; lists?: (string | null)[] | null | undefined; }, void>;
"\n mutation DeleteEntry($id: Int!) {\n DeleteMediaListEntry(id: $id) {\n deleted\n }\n }\n":
TadaDocumentNode<{ DeleteMediaListEntry: { deleted: boolean | null; } | null; }, { id: number; }, void>;
"\n mutation ToggleFavourite($id: Int!) {\n ToggleFavourite(animeId: $id) { anime { nodes { id } } } \n }\n":
TadaDocumentNode<{ ToggleFavourite: { anime: { nodes: ({ id: number; } | null)[] | null; } | null; } | null; }, { id: number; }, void>;
- "\n fragment ThreadFrag on Thread @_unmask {\n id,\n title,\n body(asHtml: true),\n userId,\n replyCount,\n viewCount,\n isLocked,\n isSubscribed,\n isLiked,\n likeCount,\n repliedAt,\n createdAt,\n user {\n id,\n name,\n avatar {\n medium\n }\n },\n categories {\n id,\n name\n }\n }\n":
- TadaDocumentNode<{ id: number; title: string | null; body: string | null; userId: number; replyCount: number | null; viewCount: number | null; isLocked: boolean | null; isSubscribed: boolean | null; isLiked: boolean | null; likeCount: number; repliedAt: number | null; createdAt: number; user: { id: number; name: string; avatar: { medium: string | null; } | null; } | null; categories: ({ id: number; name: string; } | null)[] | null; }, {}, { fragment: "ThreadFrag"; on: "Thread"; masked: false; }>;
+ "\n fragment ThreadFrag on Thread @_unmask {\n id,\n title,\n body,\n userId,\n replyCount,\n viewCount,\n isLocked,\n isSubscribed,\n isLiked,\n likeCount,\n repliedAt,\n createdAt,\n user {\n ...UserFrag\n },\n categories {\n id,\n name\n }\n }\n":
+ TadaDocumentNode<{ id: number; title: string | null; body: string | null; userId: number; replyCount: number | null; viewCount: number | null; isLocked: boolean | null; isSubscribed: boolean | null; isLiked: boolean | null; likeCount: number; repliedAt: number | null; createdAt: number; user: { id: number; bannerImage: string | null; about: string | null; isFollowing: boolean | null; isFollower: boolean | null; donatorBadge: string | null; options: { profileColor: string | null; } | null; createdAt: number | null; name: string; avatar: { medium: string | null; } | null; statistics: { anime: { count: number; minutesWatched: number; episodesWatched: number; genres: ({ genre: string | null; count: number; } | null)[] | null; } | null; } | null; } | null; categories: ({ id: number; name: string; } | null)[] | null; }, {}, { fragment: "ThreadFrag"; on: "Thread"; masked: false; }>;
"\n query Threads($id: Int!, $page: Int, $perPage: Int) {\n Page(page: $page, perPage: $perPage) {\n pageInfo {\n hasNextPage\n },\n threads(mediaCategoryId: $id, sort: ID_DESC) {\n ...ThreadFrag\n }\n }\n }\n":
- TadaDocumentNode<{ Page: { pageInfo: { hasNextPage: boolean | null; } | null; threads: ({ id: number; title: string | null; body: string | null; userId: number; replyCount: number | null; viewCount: number | null; isLocked: boolean | null; isSubscribed: boolean | null; isLiked: boolean | null; likeCount: number; repliedAt: number | null; createdAt: number; user: { id: number; name: string; avatar: { medium: string | null; } | null; } | null; categories: ({ id: number; name: string; } | null)[] | null; } | null)[] | null; } | null; }, { perPage?: number | null | undefined; page?: number | null | undefined; id: number; }, void>;
+ TadaDocumentNode<{ Page: { pageInfo: { hasNextPage: boolean | null; } | null; threads: ({ id: number; title: string | null; body: string | null; userId: number; replyCount: number | null; viewCount: number | null; isLocked: boolean | null; isSubscribed: boolean | null; isLiked: boolean | null; likeCount: number; repliedAt: number | null; createdAt: number; user: { id: number; bannerImage: string | null; about: string | null; isFollowing: boolean | null; isFollower: boolean | null; donatorBadge: string | null; options: { profileColor: string | null; } | null; createdAt: number | null; name: string; avatar: { medium: string | null; } | null; statistics: { anime: { count: number; minutesWatched: number; episodesWatched: number; genres: ({ genre: string | null; count: number; } | null)[] | null; } | null; } | null; } | null; categories: ({ id: number; name: string; } | null)[] | null; } | null)[] | null; } | null; }, { perPage?: number | null | undefined; page?: number | null | undefined; id: number; }, void>;
"\n query Thread($threadId: Int!) {\n Thread(id: $threadId) {\n ...ThreadFrag\n }\n }\n":
- TadaDocumentNode<{ Thread: { id: number; title: string | null; body: string | null; userId: number; replyCount: number | null; viewCount: number | null; isLocked: boolean | null; isSubscribed: boolean | null; isLiked: boolean | null; likeCount: number; repliedAt: number | null; createdAt: number; user: { id: number; name: string; avatar: { medium: string | null; } | null; } | null; categories: ({ id: number; name: string; } | null)[] | null; } | null; }, { threadId: number; }, void>;
- "\n fragment CommentFrag on ThreadComment @_unmask {\n id,\n comment(asHtml: true),\n isLiked,\n likeCount,\n createdAt,\n user {\n id,\n name,\n moderatorRoles,\n avatar {\n medium\n },\n },\n childComments{\n id\n },\n isLocked\n }\n":
- TadaDocumentNode<{ id: number; comment: string | null; isLiked: boolean | null; likeCount: number; createdAt: number; user: { id: number; name: string; moderatorRoles: ("ADMIN" | "LEAD_DEVELOPER" | "DEVELOPER" | "LEAD_COMMUNITY" | "COMMUNITY" | "DISCORD_COMMUNITY" | "LEAD_ANIME_DATA" | "ANIME_DATA" | "LEAD_MANGA_DATA" | "MANGA_DATA" | "LEAD_SOCIAL_MEDIA" | "SOCIAL_MEDIA" | "RETIRED" | "CHARACTER_DATA" | "STAFF_DATA" | null)[] | null; avatar: { medium: string | null; } | null; } | null; childComments: unknown; isLocked: boolean | null; }, {}, { fragment: "CommentFrag"; on: "ThreadComment"; masked: false; }>;
- "\n query Comments($threadId: Int, $page: Int) {\n Page(page: $page, perPage: 15) {\n pageInfo {\n hasNextPage\n }\n threadComments(threadId: $threadId) {\n id,\n comment(asHtml: true),\n isLiked,\n likeCount,\n createdAt,\n user {\n id,\n name,\n moderatorRoles,\n avatar {\n medium\n },\n },\n childComments{\n id\n },\n isLocked\n }\n }\n }\n":
- TadaDocumentNode<{ Page: { pageInfo: { hasNextPage: boolean | null; } | null; threadComments: ({ id: number; comment: string | null; isLiked: boolean | null; likeCount: number; createdAt: number; user: { id: number; name: string; moderatorRoles: ("ADMIN" | "LEAD_DEVELOPER" | "DEVELOPER" | "LEAD_COMMUNITY" | "COMMUNITY" | "DISCORD_COMMUNITY" | "LEAD_ANIME_DATA" | "ANIME_DATA" | "LEAD_MANGA_DATA" | "MANGA_DATA" | "LEAD_SOCIAL_MEDIA" | "SOCIAL_MEDIA" | "RETIRED" | "CHARACTER_DATA" | "STAFF_DATA" | null)[] | null; avatar: { medium: string | null; } | null; } | null; childComments: unknown; isLocked: boolean | null; } | null)[] | null; } | null; }, { page?: number | null | undefined; threadId?: number | null | undefined; }, void>;
- "\n query User ($id: Int) {\n User(id: $id) {\n id,\n name,\n avatar {\n large\n },\n bannerImage,\n about(asHtml: true),\n isFollowing,\n isFollower,\n donatorBadge,\n createdAt,\n options {\n profileColor\n },\n statistics {\n anime {\n count,\n minutesWatched,\n episodesWatched,\n genrePreview: genres(limit: 10, sort: COUNT_DESC) {\n genre,\n count\n }\n }\n }\n }\n }\n":
- TadaDocumentNode<{ User: { id: number; name: string; avatar: { large: string | null; } | null; bannerImage: string | null; about: string | null; isFollowing: boolean | null; isFollower: boolean | null; donatorBadge: string | null; createdAt: number | null; options: { profileColor: string | null; } | null; statistics: { anime: { count: number; minutesWatched: number; episodesWatched: number; genrePreview: ({ genre: string | null; count: number; } | null)[] | null; } | null; } | null; } | null; }, { id?: number | null | undefined; }, void>;
+ TadaDocumentNode<{ Thread: { id: number; title: string | null; body: string | null; userId: number; replyCount: number | null; viewCount: number | null; isLocked: boolean | null; isSubscribed: boolean | null; isLiked: boolean | null; likeCount: number; repliedAt: number | null; createdAt: number; user: { id: number; bannerImage: string | null; about: string | null; isFollowing: boolean | null; isFollower: boolean | null; donatorBadge: string | null; options: { profileColor: string | null; } | null; createdAt: number | null; name: string; avatar: { medium: string | null; } | null; statistics: { anime: { count: number; minutesWatched: number; episodesWatched: number; genres: ({ genre: string | null; count: number; } | null)[] | null; } | null; } | null; } | null; categories: ({ id: number; name: string; } | null)[] | null; } | null; }, { threadId: number; }, void>;
+ "\n fragment CommentFrag on ThreadComment @_unmask {\n id,\n comment,\n isLiked,\n likeCount,\n createdAt,\n user {\n ...UserFrag\n },\n childComments,\n isLocked\n }\n":
+ TadaDocumentNode<{ id: number; comment: string | null; isLiked: boolean | null; likeCount: number; createdAt: number; user: { id: number; bannerImage: string | null; about: string | null; isFollowing: boolean | null; isFollower: boolean | null; donatorBadge: string | null; options: { profileColor: string | null; } | null; createdAt: number | null; name: string; avatar: { medium: string | null; } | null; statistics: { anime: { count: number; minutesWatched: number; episodesWatched: number; genres: ({ genre: string | null; count: number; } | null)[] | null; } | null; } | null; } | null; childComments: unknown; isLocked: boolean | null; }, {}, { fragment: "CommentFrag"; on: "ThreadComment"; masked: false; }>;
+ "\n query Comments($threadId: Int, $page: Int) {\n Page(page: $page, perPage: 15) {\n pageInfo {\n hasNextPage\n }\n threadComments(threadId: $threadId) {\n id,\n comment,\n isLiked,\n likeCount,\n createdAt,\n user {\n id,\n name,\n avatar {\n medium\n },\n },\n childComments,\n isLocked\n }\n }\n }\n":
+ TadaDocumentNode<{ Page: { pageInfo: { hasNextPage: boolean | null; } | null; threadComments: ({ id: number; comment: string | null; isLiked: boolean | null; likeCount: number; createdAt: number; user: { id: number; name: string; avatar: { medium: string | null; } | null; } | null; childComments: unknown; isLocked: boolean | null; } | null)[] | null; } | null; }, { page?: number | null | undefined; threadId?: number | null | undefined; }, void>;
"\n mutation ToggleLike ($id: Int!, $type: LikeableType!) {\n ToggleLikeV2(id: $id, type: $type) {\n ... on Thread {\n id\n likeCount\n isLiked\n }\n ... on ThreadComment {\n id\n likeCount\n isLiked\n }\n }\n }\n":
TadaDocumentNode<{ ToggleLikeV2: { __typename?: "ActivityReply" | undefined; } | { __typename?: "ListActivity" | undefined; } | { __typename?: "MessageActivity" | undefined; } | { __typename?: "TextActivity" | undefined; } | { __typename?: "Thread" | undefined; id: number; likeCount: number; isLiked: boolean | null; } | { __typename?: "ThreadComment" | undefined; id: number; likeCount: number; isLiked: boolean | null; } | null; }, { type: "THREAD" | "THREAD_COMMENT" | "ACTIVITY" | "ACTIVITY_REPLY"; id: number; }, void>;
"\n mutation SaveThreadComment ($id: Int, $threadId: Int, $parentCommentId: Int, $comment: String) {\n SaveThreadComment(id: $id, threadId: $threadId, parentCommentId: $parentCommentId, comment: $comment) {\n ...CommentFrag\n }\n }\n":
- TadaDocumentNode<{ SaveThreadComment: { id: number; comment: string | null; isLiked: boolean | null; likeCount: number; createdAt: number; user: { id: number; name: string; moderatorRoles: ("ADMIN" | "LEAD_DEVELOPER" | "DEVELOPER" | "LEAD_COMMUNITY" | "COMMUNITY" | "DISCORD_COMMUNITY" | "LEAD_ANIME_DATA" | "ANIME_DATA" | "LEAD_MANGA_DATA" | "MANGA_DATA" | "LEAD_SOCIAL_MEDIA" | "SOCIAL_MEDIA" | "RETIRED" | "CHARACTER_DATA" | "STAFF_DATA" | null)[] | null; avatar: { medium: string | null; } | null; } | null; childComments: unknown; isLocked: boolean | null; } | null; }, { comment?: string | null | undefined; parentCommentId?: number | null | undefined; threadId?: number | null | undefined; id?: number | null | undefined; }, void>;
+ TadaDocumentNode<{ SaveThreadComment: { id: number; comment: string | null; isLiked: boolean | null; likeCount: number; createdAt: number; user: { id: number; bannerImage: string | null; about: string | null; isFollowing: boolean | null; isFollower: boolean | null; donatorBadge: string | null; options: { profileColor: string | null; } | null; createdAt: number | null; name: string; avatar: { medium: string | null; } | null; statistics: { anime: { count: number; minutesWatched: number; episodesWatched: number; genres: ({ genre: string | null; count: number; } | null)[] | null; } | null; } | null; } | null; childComments: unknown; isLocked: boolean | null; } | null; }, { comment?: string | null | undefined; parentCommentId?: number | null | undefined; threadId?: number | null | undefined; id?: number | null | undefined; }, void>;
"\n mutation DeleteThreadComment ($id: Int) {\n DeleteThreadComment(id: $id) {\n deleted\n }\n }\n":
TadaDocumentNode<{ DeleteThreadComment: { deleted: boolean | null; } | null; }, { id?: number | null | undefined; }, void>;
"fragment Med on Media {id, isFavourite}":
diff --git a/src/lib/modules/anilist/queries.ts b/src/lib/modules/anilist/queries.ts
index 060a7e0..c98d765 100644
--- a/src/lib/modules/anilist/queries.ts
+++ b/src/lib/modules/anilist/queries.ts
@@ -250,6 +250,36 @@ export const Schedule = gql(`
}
`, [ScheduleMedia])
+export const UserFrag = gql(`
+ fragment UserFrag on User @_unmask {
+ id,
+ bannerImage,
+ about,
+ isFollowing,
+ isFollower,
+ donatorBadge,
+ options {
+ profileColor
+ },
+ createdAt,
+ name,
+ avatar {
+ medium
+ },
+ statistics {
+ anime {
+ count,
+ minutesWatched,
+ episodesWatched,
+ genres(limit: 3, sort: COUNT_DESC) {
+ genre,
+ count
+ }
+ }
+ }
+ }
+`)
+
export const Following = gql(`
query Following($id: Int!) {
Page {
@@ -259,16 +289,12 @@ export const Following = gql(`
score,
progress,
user {
- id,
- name,
- avatar {
- medium
- }
+ ...UserFrag
}
}
}
}
-`)
+`, [UserFrag])
// AL API is dog, fullmedialist is NULL when queried inside media..., it's possible this can cause cache loops, but there's no other way to do this!!!
export const Entry = gql(`
@@ -312,18 +338,14 @@ export const ThreadFrag = gql(`
repliedAt,
createdAt,
user {
- id,
- name,
- avatar {
- medium
- }
+ ...UserFrag
},
categories {
id,
name
}
}
-`)
+`, [UserFrag])
export const Threads = gql(`
query Threads($id: Int!, $page: Int, $perPage: Int) {
@@ -354,17 +376,12 @@ export const CommentFrag = gql(`
likeCount,
createdAt,
user {
- id,
- name,
- moderatorRoles,
- avatar {
- medium
- },
+ ...UserFrag
},
childComments,
isLocked
}
-`)
+`, [UserFrag])
// AL in their infinite wisdom decided to make childComments infer the schema of the parent comment, so we can't use the CommentFrag here
export const Comments = gql(`
@@ -380,51 +397,14 @@ export const Comments = gql(`
likeCount,
createdAt,
user {
- id,
- name,
- moderatorRoles,
- avatar {
- medium
- },
+ ...UserFrag
},
childComments,
isLocked
}
}
}
-`)
-
-export const User = gql(`
- query User ($id: Int) {
- User(id: $id) {
- id,
- name,
- avatar {
- large
- },
- bannerImage,
- about,
- isFollowing,
- isFollower,
- donatorBadge,
- createdAt,
- options {
- profileColor
- },
- statistics {
- anime {
- count,
- minutesWatched,
- episodesWatched,
- genrePreview: genres(limit: 10, sort: COUNT_DESC) {
- genre,
- count
- }
- }
- }
- }
- }
-`)
+`, [UserFrag])
export const ToggleLike = gql(`
mutation ToggleLike ($id: Int!, $type: LikeableType!) {
diff --git a/src/lib/modules/navigate.ts b/src/lib/modules/navigate.ts
index dd5cd89..d90e3f9 100644
--- a/src/lib/modules/navigate.ts
+++ b/src/lib/modules/navigate.ts
@@ -26,6 +26,7 @@ for (const { pointer, value } of pointerTypes) {
const noop: () => void = () => undefined
+// this is for nested click elements, its svelte's |preventDefault for other components
export function clickwrap (cb: (_: MouseEvent) => unknown = noop) {
return (e: MouseEvent) => {
e.stopPropagation()
diff --git a/src/routes/app/anime/[id]/+layout.svelte b/src/routes/app/anime/[id]/+layout.svelte
index 07e3a94..0b76d9b 100644
--- a/src/routes/app/anime/[id]/+layout.svelte
+++ b/src/routes/app/anime/[id]/+layout.svelte
@@ -8,12 +8,11 @@
import Anilist from '$lib/components/icons/Anilist.svelte'
import MyAnimeList from '$lib/components/icons/MyAnimeList.svelte'
- import * as Avatar from '$lib/components/ui/avatar'
import { bannerSrc, hideBanner } from '$lib/components/ui/banner'
import { PlayButton, Button, BookmarkButton, FavoriteButton } from '$lib/components/ui/button'
import * as Dialog from '$lib/components/ui/dialog'
import { Load } from '$lib/components/ui/img'
- import * as Tooltip from '$lib/components/ui/tooltip'
+ import { Profile } from '$lib/components/ui/profile'
import { cover, desc, duration, format, season, status, title } from '$lib/modules/anilist'
import { authAggregator, of } from '$lib/modules/auth'
import native from '$lib/modules/native'
@@ -142,18 +141,9 @@
{#each followerEntries as followerEntry, i (followerEntry?.user?.id ?? i)}
-
-
-
-
- {followerEntry?.user?.name ?? 'N/A'}
-
-
-
-
- {followerEntry?.status?.toLowerCase()}
-
-
+ {#if followerEntry?.user}
+
+ {/if}
{/each}
diff --git a/src/routes/app/anime/[id]/thread/[threadId]/+page.svelte b/src/routes/app/anime/[id]/thread/[threadId]/+page.svelte
index 1fccd13..a6da454 100644
--- a/src/routes/app/anime/[id]/thread/[threadId]/+page.svelte
+++ b/src/routes/app/anime/[id]/thread/[threadId]/+page.svelte
@@ -4,9 +4,9 @@
import type { PageData } from './$types'
import Shadow from '$lib/components/Shadow.svelte'
- import * as Avatar from '$lib/components/ui/avatar'
import { Button, iconSizes } from '$lib/components/ui/button'
import { Comments, Write } from '$lib/components/ui/forums'
+ import { Profile } from '$lib/components/ui/profile'
import { client } from '$lib/modules/anilist'
import { since } from '$lib/utils'
@@ -46,11 +46,10 @@