Skip to content

Commit 9c3b599

Browse files
authored
feat: improve episodes table appearance (#183)
1 parent 9d3b116 commit 9c3b599

File tree

3 files changed

+105
-26
lines changed

3 files changed

+105
-26
lines changed

front/src/features/show/EpisodesTable.tsx

Lines changed: 69 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
1-
import { Table, Text } from '@chakra-ui/react';
1+
import { Badge, Flex, Icon, Table, Text } from '@chakra-ui/react';
22
import {
33
ColumnDef,
44
flexRender,
55
getCoreRowModel,
66
useReactTable,
77
} from '@tanstack/react-table';
8+
import { FaStar } from 'react-icons/fa';
89

910
import { useIsMobile } from '~/hooks/useIsMobile';
1011
import { EpisodeForSeason } from '~/store/tv/types/transformed';
1112
import dayjs from '~/utils/dayjs';
1213

14+
import TableHeader from './TableHeader';
15+
1316
type Props = {
1417
episodes: EpisodeForSeason[];
1518
};
@@ -22,36 +25,71 @@ const EpisodesTable = ({ episodes }: Props) => {
2225
id: 'episodeNumber',
2326
accessorKey: 'episodeNumber',
2427
size: 40,
25-
header: () => <Text color="fg.muted">#</Text>,
28+
header: () => <TableHeader>Number</TableHeader>,
29+
cell: ({ row }) => (
30+
<Text color="fg.muted" fontSize="sm">
31+
{row.original.episodeNumber}
32+
</Text>
33+
),
2634
},
2735
{
2836
id: 'name',
2937
accessorKey: 'name',
3038
size: 100,
31-
header: () => <Text color="fg.muted">Title</Text>,
39+
header: () => <TableHeader>Title</TableHeader>,
40+
cell: ({ row }) => (
41+
<Text fontWeight="semibold" fontSize="sm" color="fg">
42+
{row.original.name}
43+
</Text>
44+
),
3245
},
3346
{
3447
id: 'airDate',
3548
size: 80,
3649
accessorFn: row =>
37-
row.airDate && dayjs(row.airDate).format('MMMM D, YYYY'),
38-
header: () => <Text color="fg.muted">Air Date</Text>,
50+
row.airDate && dayjs(row.airDate).format('MMM D, YYYY'),
51+
header: () => <TableHeader>Air Date</TableHeader>,
52+
cell: ({ getValue }) => (
53+
<Text fontSize="sm" whiteSpace="nowrap" color="fg.muted">
54+
{getValue() as string}
55+
</Text>
56+
),
3957
},
4058
{
4159
id: 'voteAverage',
4260
size: 50,
43-
meta: {
44-
style: { textAlign: 'center' },
61+
header: () => <TableHeader textAlign="center">Rating</TableHeader>,
62+
cell: ({ row }) => {
63+
const ratingStr = row.original.voteAverage;
64+
if (!ratingStr || ratingStr === '-') {
65+
return (
66+
<Text color="fg.muted" textAlign="center">
67+
-
68+
</Text>
69+
);
70+
}
71+
const rating = parseFloat(ratingStr);
72+
73+
return (
74+
<Flex justify="center">
75+
<Badge
76+
variant="subtle"
77+
colorPalette={
78+
rating >= 8 ? 'green' : rating >= 6.5 ? 'yellow' : 'orange'
79+
}
80+
size="sm"
81+
borderRadius="full"
82+
px="2"
83+
display="flex"
84+
alignItems="center"
85+
gap="1"
86+
>
87+
{rating.toFixed(1)}
88+
<Icon as={FaStar} boxSize="2" />
89+
</Badge>
90+
</Flex>
91+
);
4592
},
46-
accessorFn: row => row.voteAverage,
47-
header: () => (
48-
<Text color="fg.muted" textAlign="center">
49-
Rating
50-
</Text>
51-
),
52-
cell: ({ row }) => (
53-
<Text textAlign="center">{row.original.voteAverage}</Text>
54-
),
5593
},
5694
];
5795

@@ -67,12 +105,16 @@ const EpisodesTable = ({ episodes }: Props) => {
67105
});
68106

69107
return (
70-
<Table.Root size="sm">
108+
<Table.Root size={isMobile ? 'sm' : 'md'} variant="outline" interactive>
71109
<Table.Header>
72110
{getHeaderGroups().map(headerGroup => (
73-
<Table.Row key={headerGroup.id}>
111+
<Table.Row key={headerGroup.id} borderBottomWidth="2px">
74112
{headerGroup.headers.map(header => (
75-
<Table.ColumnHeader key={header.id}>
113+
<Table.ColumnHeader
114+
key={header.id}
115+
py="4"
116+
px={isMobile ? '2' : '4'}
117+
>
76118
{header.isPlaceholder
77119
? null
78120
: flexRender(
@@ -87,9 +129,15 @@ const EpisodesTable = ({ episodes }: Props) => {
87129

88130
<Table.Body>
89131
{getRowModel().rows.map(row => (
90-
<Table.Row key={row.id}>
132+
<Table.Row
133+
key={row.id}
134+
_hover={{ bg: 'whiteAlpha.50' }}
135+
transition="background 0.2s"
136+
borderBottomWidth="1px"
137+
borderColor="whiteAlpha.50"
138+
>
91139
{row.getVisibleCells().map(cell => (
92-
<Table.Cell key={cell.id}>
140+
<Table.Cell key={cell.id} py="4" px={isMobile ? '2' : '4'}>
93141
{flexRender(cell.column.columnDef.cell, cell.getContext())}
94142
</Table.Cell>
95143
))}

front/src/features/show/SeasonAccordionGroup.tsx

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,27 +22,39 @@ const SeasonAccordionGroup = () => {
2222
const createAccordionItems = () =>
2323
seasonsWithEpisodes?.map(
2424
({ airDate, episodes, id, isSpecialsSeason, nameForDisplay }) => (
25-
<Accordion.Item key={id} value={id.toString()}>
25+
<Accordion.Item
26+
key={id}
27+
value={id.toString()}
28+
borderBottomWidth="1px"
29+
borderColor="whiteAlpha.100"
30+
_last={{ borderBottomWidth: 0 }}
31+
>
2632
<Accordion.ItemTrigger
2733
cursor="pointer"
2834
px={isMobile ? '8px' : '16px'}
35+
py={4}
36+
_hover={{ bg: 'whiteAlpha.50' }}
37+
_open={{ bg: 'whiteAlpha.50' }}
38+
transition="background 0.2s"
2939
>
3040
<Box flex="1" textAlign="left">
31-
<Text display="inline" fontSize="lg" fontWeight="600">
41+
<Text display="inline" fontSize="lg" fontWeight="600" color="fg">
3242
{nameForDisplay}
3343
</Text>{' '}
3444
{!isSpecialsSeason && airDate && (
35-
<Text display="inline" fontSize="md">
45+
<Text display="inline" fontSize="md" color="fg.muted" ml={0.5}>
3646
({dayjs(airDate).year()})
3747
</Text>
3848
)}
3949
</Box>
4050
<Box mr="20px" textAlign="right">
41-
<Text fontSize="md">{episodes.length} Episodes</Text>
51+
<Text fontSize="sm" color="fg.muted">
52+
{episodes.length} Episodes
53+
</Text>
4254
</Box>
4355
<Accordion.ItemIndicator />
4456
</Accordion.ItemTrigger>
45-
<Accordion.ItemContent p={isMobile ? '10px 0 5px' : '10px'}>
57+
<Accordion.ItemContent>
4658
<EpisodesTable episodes={episodes} />
4759
</Accordion.ItemContent>
4860
</Accordion.Item>
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { Text, TextProps } from '@chakra-ui/react';
2+
import { ReactNode } from 'react';
3+
4+
const TableHeader = ({
5+
children,
6+
...textProps
7+
}: { children: ReactNode } & TextProps) => (
8+
<Text
9+
color="fg.muted"
10+
fontSize="xs"
11+
fontWeight="bold"
12+
textTransform="uppercase"
13+
{...textProps}
14+
>
15+
{children}
16+
</Text>
17+
);
18+
19+
export default TableHeader;

0 commit comments

Comments
 (0)