A decentralized music tracking and discovery platform built on AT Protocol 🎵

Add skeleton loaders for genre pages

+117
+34
apps/web/src/pages/genre/albums/Albums.tsx
··· 6 6 import dayjs from "dayjs"; 7 7 import { useEffect, useRef } from "react"; 8 8 import { LabelSmall } from "baseui/typography"; 9 + import ContentLoader from "react-content-loader"; 9 10 10 11 const itemProps: BlockProps = { 11 12 display: "flex", ··· 42 43 43 44 return ( 44 45 <> 46 + {isLoading && ( 47 + <FlexGrid 48 + flexGridColumnCount={[1, 2, 3]} 49 + flexGridColumnGap="scale800" 50 + flexGridRowGap="scale1000" 51 + className="mt-[50px]" 52 + > 53 + {/* Generate 12 skeleton items (4 rows x 3 columns) */} 54 + {[...Array(12)].map((_, index) => ( 55 + <FlexGridItem {...itemProps} key={index}> 56 + <ContentLoader 57 + width={230} 58 + height={330} 59 + viewBox="0 0 230 330" 60 + backgroundColor="var(--color-skeleton-background)" 61 + foregroundColor="var(--color-skeleton-foreground)" 62 + > 63 + {/* Square for album art */} 64 + <rect x="0" y="0" rx="4" ry="4" width="230" height="230" /> 65 + {/* Album title - 2 lines */} 66 + <rect x="0" y="250" rx="3" ry="3" width="200" height="12" /> 67 + <rect x="0" y="268" rx="3" ry="3" width="150" height="12" /> 68 + {/* Artist name */} 69 + <rect x="0" y="290" rx="3" ry="3" width="120" height="10" /> 70 + {/* Play count */} 71 + <rect x="0" y="308" rx="3" ry="3" width="100" height="10" /> 72 + {/* Release date */} 73 + <rect x="0" y="323" rx="3" ry="3" width="130" height="10" /> 74 + </ContentLoader> 75 + </FlexGridItem> 76 + ))} 77 + </FlexGrid> 78 + )} 45 79 {!isLoading && ( 46 80 <> 47 81 <FlexGrid
+29
apps/web/src/pages/genre/artists/Artists.tsx
··· 6 6 import { useEffect, useRef } from "react"; 7 7 import { LabelSmall } from "baseui/typography"; 8 8 import ArtistIcon from "../../../components/Icons/Artist"; 9 + import ContentLoader from "react-content-loader"; 9 10 10 11 const itemProps: BlockProps = { 11 12 display: "flex", ··· 42 43 43 44 return ( 44 45 <> 46 + {isLoading && ( 47 + <FlexGrid 48 + flexGridColumnCount={[1, 2, 3]} 49 + flexGridColumnGap="scale800" 50 + flexGridRowGap="scale1000" 51 + className="mt-[50px]" 52 + > 53 + {/* Generate 9 skeleton items (3x3 grid) */} 54 + {[...Array(9)].map((_, index) => ( 55 + <FlexGridItem {...itemProps} key={index}> 56 + <ContentLoader 57 + width={200} 58 + height={250} 59 + viewBox="0 0 200 250" 60 + backgroundColor="var(--color-skeleton-background)" 61 + foregroundColor="var(--color-skeleton-foreground)" 62 + > 63 + {/* Circle for artist avatar */} 64 + <circle cx="100" cy="100" r="100" /> 65 + {/* Artist name */} 66 + <rect x="50" y="220" rx="3" ry="3" width="100" height="12" /> 67 + {/* Play count */} 68 + <rect x="60" y="240" rx="3" ry="3" width="80" height="10" /> 69 + </ContentLoader> 70 + </FlexGridItem> 71 + ))} 72 + </FlexGrid> 73 + )} 45 74 {!isLoading && ( 46 75 <> 47 76 <FlexGrid
+54
apps/web/src/pages/genre/tracks/Tracks.tsx
··· 4 4 import numeral from "numeral"; 5 5 import { useEffect, useRef } from "react"; 6 6 import { LabelSmall } from "baseui/typography"; 7 + import ContentLoader from "react-content-loader"; 7 8 8 9 type Row = { 9 10 id: string; ··· 47 48 48 49 return ( 49 50 <> 51 + {isLoading && ( 52 + <div className="ml-[-150px] mt-[20px]"> 53 + <ContentLoader 54 + width="100%" 55 + height={500} 56 + viewBox="0 0 600 500" 57 + backgroundColor="var(--color-skeleton-background)" 58 + foregroundColor="var(--color-skeleton-foreground)" 59 + > 60 + {/* Row 1 */} 61 + <rect x="0" y="10" rx="3" ry="3" width="30" height="15" /> 62 + <rect x="50" y="5" rx="4" ry="4" width="60" height="60" /> 63 + <rect x="130" y="15" rx="3" ry="3" width="200" height="15" /> 64 + <rect x="130" y="40" rx="3" ry="3" width="150" height="12" /> 65 + <rect x="500" y="20" rx="3" ry="3" width="80" height="15" /> 66 + 67 + {/* Row 2 */} 68 + <rect x="0" y="90" rx="3" ry="3" width="30" height="15" /> 69 + <rect x="50" y="85" rx="4" ry="4" width="60" height="60" /> 70 + <rect x="130" y="95" rx="3" ry="3" width="200" height="15" /> 71 + <rect x="130" y="120" rx="3" ry="3" width="150" height="12" /> 72 + <rect x="500" y="100" rx="3" ry="3" width="80" height="15" /> 73 + 74 + {/* Row 3 */} 75 + <rect x="0" y="170" rx="3" ry="3" width="30" height="15" /> 76 + <rect x="50" y="165" rx="4" ry="4" width="60" height="60" /> 77 + <rect x="130" y="175" rx="3" ry="3" width="200" height="15" /> 78 + <rect x="130" y="200" rx="3" ry="3" width="150" height="12" /> 79 + <rect x="500" y="180" rx="3" ry="3" width="80" height="15" /> 80 + 81 + {/* Row 4 */} 82 + <rect x="0" y="250" rx="3" ry="3" width="30" height="15" /> 83 + <rect x="50" y="245" rx="4" ry="4" width="60" height="60" /> 84 + <rect x="130" y="255" rx="3" ry="3" width="200" height="15" /> 85 + <rect x="130" y="280" rx="3" ry="3" width="150" height="12" /> 86 + <rect x="500" y="260" rx="3" ry="3" width="80" height="15" /> 87 + 88 + {/* Row 5 */} 89 + <rect x="0" y="330" rx="3" ry="3" width="30" height="15" /> 90 + <rect x="50" y="325" rx="4" ry="4" width="60" height="60" /> 91 + <rect x="130" y="335" rx="3" ry="3" width="200" height="15" /> 92 + <rect x="130" y="360" rx="3" ry="3" width="150" height="12" /> 93 + <rect x="500" y="340" rx="3" ry="3" width="80" height="15" /> 94 + 95 + {/* Row 6 */} 96 + <rect x="0" y="410" rx="3" ry="3" width="30" height="15" /> 97 + <rect x="50" y="405" rx="4" ry="4" width="60" height="60" /> 98 + <rect x="130" y="415" rx="3" ry="3" width="200" height="15" /> 99 + <rect x="130" y="440" rx="3" ry="3" width="150" height="12" /> 100 + <rect x="500" y="420" rx="3" ry="3" width="80" height="15" /> 101 + </ContentLoader> 102 + </div> 103 + )} 50 104 {!isLoading && ( 51 105 <> 52 106 <TableBuilder