5
5
Container ,
6
6
Flex ,
7
7
Group ,
8
+ Image ,
8
9
Pagination ,
9
- Paper ,
10
10
Stack ,
11
11
Text ,
12
12
Title ,
@@ -17,15 +17,23 @@ import {
17
17
type MetaArgs_SingleFetch ,
18
18
useLoaderData ,
19
19
} from "@remix-run/react" ;
20
- import { GenresListDocument } from "@ryot/generated/graphql/backend/graphql" ;
21
- import { truncate } from "@ryot/ts-utils" ;
20
+ import {
21
+ GenresListDocument ,
22
+ type GenresListQuery ,
23
+ } from "@ryot/generated/graphql/backend/graphql" ;
24
+ import { getInitials , truncate } from "@ryot/ts-utils" ;
22
25
import { $path } from "remix-routes" ;
23
26
import { z } from "zod" ;
24
27
import { zx } from "zodix" ;
25
- import { ApplicationGrid , DebouncedSearchInput } from "~/components/common" ;
28
+ import {
29
+ ApplicationGrid ,
30
+ DebouncedSearchInput ,
31
+ ProRequiredAlert ,
32
+ } from "~/components/common" ;
26
33
import {
27
34
useAppSearchParam ,
28
35
useCoreDetails ,
36
+ useFallbackImageUrl ,
29
37
useGetMantineColor ,
30
38
} from "~/lib/hooks" ;
31
39
import {
@@ -60,7 +68,6 @@ export const meta = (_args: MetaArgs_SingleFetch<typeof loader>) => {
60
68
export default function Page ( ) {
61
69
const loaderData = useLoaderData < typeof loader > ( ) ;
62
70
const coreDetails = useCoreDetails ( ) ;
63
- const getMantineColor = useGetMantineColor ( ) ;
64
71
const [ _ , { setP } ] = useAppSearchParam ( loaderData . cookieName ) ;
65
72
66
73
return (
@@ -84,27 +91,7 @@ export default function Page() {
84
91
</ Box >
85
92
< ApplicationGrid >
86
93
{ loaderData . genresList . items . map ( ( genre ) => (
87
- < Paper key = { genre . id } >
88
- < Group >
89
- < Box
90
- h = { 11 }
91
- w = { 11 }
92
- style = { { borderRadius : 2 } }
93
- bg = { getMantineColor ( genre . name ) }
94
- />
95
- < Box >
96
- < Anchor
97
- component = { Link }
98
- to = { $path ( "/media/genre/:id" , { id : genre . id } ) }
99
- >
100
- { truncate ( genre . name , { length : 13 } ) }
101
- </ Anchor >
102
- < Text size = "sm" c = "dimmed" >
103
- { genre . numItems } items
104
- </ Text >
105
- </ Box >
106
- </ Group >
107
- </ Paper >
94
+ < DisplayGenre key = { genre . id } genre = { genre } />
108
95
) ) }
109
96
</ ApplicationGrid >
110
97
</ >
@@ -127,3 +114,39 @@ export default function Page() {
127
114
</ Container >
128
115
) ;
129
116
}
117
+
118
+ type Genre = GenresListQuery [ "genresList" ] [ "items" ] [ number ] ;
119
+
120
+ const DisplayGenre = ( props : { genre : Genre } ) => {
121
+ const getMantineColor = useGetMantineColor ( ) ;
122
+
123
+ return (
124
+ < Anchor
125
+ component = { Link }
126
+ to = { $path ( "/media/genre/:id" , { id : props . genre . id } ) }
127
+ >
128
+ < Stack gap = { 4 } >
129
+ < Box pos = "relative" >
130
+ < Image
131
+ radius = "md"
132
+ h = { 260 }
133
+ alt = { props . genre . name }
134
+ fallbackSrc = { useFallbackImageUrl ( getInitials ( props . genre . name ) ) }
135
+ />
136
+ < Box pos = "absolute" left = { 0 } right = { 0 } bottom = { 0 } >
137
+ < ProRequiredAlert tooltipLabel = "Collage image using genre contents" />
138
+ </ Box >
139
+ </ Box >
140
+ < Group justify = "center" >
141
+ < Box
142
+ h = { 11 }
143
+ w = { 11 }
144
+ style = { { borderRadius : 2 } }
145
+ bg = { getMantineColor ( props . genre . name ) }
146
+ />
147
+ < Text > { truncate ( props . genre . name , { length : 13 } ) } </ Text >
148
+ </ Group >
149
+ </ Stack >
150
+ </ Anchor >
151
+ ) ;
152
+ } ;
0 commit comments