Spaces:
Running
Running
| import type { ColumnDef, RowData } from '@tanstack/table-core'; | |
| import { renderComponent } from '$lib/components/ui/data-table'; | |
| import SortHeader from './data-table-sort-header.svelte'; | |
| import PlainHeader from './data-table-plain-header.svelte'; | |
| import EventCell from './cells/event-cell.svelte'; | |
| import MatchIdCell from './cells/match-id-cell.svelte'; | |
| import TeamsCell from './cells/teams-cell.svelte'; | |
| import ScoreCell from './cells/score-cell.svelte'; | |
| import MapCell from './cells/map-cell.svelte'; | |
| import MapsListCell from './cells/maps-list-cell.svelte'; | |
| import WinnerSideCell from './cells/winner-side-cell.svelte'; | |
| import DurationCell from './cells/duration-cell.svelte'; | |
| import DateCell from './cells/date-cell.svelte'; | |
| import RoundCell from './cells/round-cell.svelte'; | |
| import RoundsPlayedCell from './cells/rounds-played-cell.svelte'; | |
| import PlayerCell from './cells/player-cell.svelte'; | |
| import StartTimeCell from './cells/start-time-cell.svelte'; | |
| import type { MapRow, MatchRow, PovRow, RoundRow } from './rows'; | |
| import type { Match } from '$lib/types'; | |
| declare module '@tanstack/table-core' { | |
| interface ColumnMeta<TData extends RowData, TValue> { | |
| label?: string; | |
| cellClass?: string; | |
| headClass?: string; | |
| } | |
| } | |
| const dateSort = (a: { match_date: string }, b: { match_date: string }) => | |
| new Date(a.match_date).getTime() - new Date(b.match_date).getTime(); | |
| const uploadedSort = (a: { uploaded_at: string }, b: { uploaded_at: string }) => | |
| new Date(a.uploaded_at).getTime() - new Date(b.uploaded_at).getTime(); | |
| const uploadedColumn = <T extends { uploaded_at: string }>(): ColumnDef<T> => ({ | |
| id: 'uploaded_at', | |
| accessorFn: (r) => new Date(r.uploaded_at).getTime(), | |
| sortingFn: (a, b) => uploadedSort(a.original, b.original), | |
| header: ({ column }) => renderComponent(SortHeader, { column, label: 'Uploaded' }), | |
| cell: ({ row }) => renderComponent(DateCell, { iso: row.original.uploaded_at }), | |
| enableGlobalFilter: false, | |
| meta: { label: 'Uploaded' } | |
| }); | |
| // Cells use `accessorFn` returning the underlying value so global filtering and | |
| // sorting see the right thing; visual rendering happens in `cell` via components. | |
| const matchIdColumn = <T extends { match_id: number }>(): ColumnDef<T> => ({ | |
| id: 'match_id', | |
| accessorKey: 'match_id', | |
| header: ({ column }) => renderComponent(SortHeader, { column, label: 'Match' }), | |
| cell: ({ row }) => renderComponent(MatchIdCell, { matchId: row.original.match_id }), | |
| meta: { label: 'Match', cellClass: 'w-[6rem] pr-2', headClass: 'w-[6rem] pr-2' } | |
| }); | |
| const eventColumn = <T extends { event: string; format?: string }>(): ColumnDef<T> => ({ | |
| id: 'event', | |
| accessorKey: 'event', | |
| header: ({ column }) => renderComponent(SortHeader, { column, label: 'Event' }), | |
| cell: ({ row }) => | |
| renderComponent(EventCell, { event: row.original.event, format: row.original.format }), | |
| meta: { | |
| label: 'Event', | |
| cellClass: 'max-w-[16rem]', | |
| headClass: 'max-w-[16rem]' | |
| } | |
| }); | |
| export const roundColumns: ColumnDef<RoundRow>[] = [ | |
| matchIdColumn<RoundRow>(), | |
| eventColumn<RoundRow>(), | |
| { | |
| id: 'map_name', | |
| accessorKey: 'map_name', | |
| header: () => renderComponent(PlainHeader, { label: 'Map' }), | |
| cell: ({ row }) => renderComponent(MapCell, { map: row.original.map_name }), | |
| enableSorting: false, | |
| filterFn: (row, id, value) => { | |
| if (!value) return true; | |
| return row.getValue<string>(id) === value; | |
| }, | |
| meta: { label: 'Map' } | |
| }, | |
| { | |
| id: 'teams', | |
| accessorFn: (r) => `${r.team1} ${r.team2}`, | |
| header: () => renderComponent(PlainHeader, { label: 'Teams' }), | |
| cell: ({ row }) => | |
| renderComponent(TeamsCell, { | |
| team1: row.original.team1, | |
| team2: row.original.team2, | |
| winner: row.original.winner | |
| }), | |
| enableSorting: false, | |
| meta: { label: 'Teams' } | |
| }, | |
| { | |
| id: 'round', | |
| accessorKey: 'round', | |
| header: ({ column }) => renderComponent(SortHeader, { column, label: 'Round' }), | |
| cell: ({ row }) => | |
| renderComponent(RoundCell, { round: row.original.round, total: row.original.rounds_played }), | |
| enableGlobalFilter: false, | |
| meta: { label: 'Round' } | |
| }, | |
| { | |
| id: 'duration_s', | |
| accessorKey: 'duration_s', | |
| header: ({ column }) => renderComponent(SortHeader, { column, label: 'Duration' }), | |
| cell: ({ row }) => renderComponent(DurationCell, { seconds: row.original.duration_s }), | |
| enableGlobalFilter: false, | |
| meta: { label: 'Duration' } | |
| }, | |
| { | |
| id: 'match_date', | |
| accessorFn: (r) => new Date(r.match_date).getTime(), | |
| sortingFn: (a, b) => dateSort(a.original, b.original), | |
| header: ({ column }) => renderComponent(SortHeader, { column, label: 'Date' }), | |
| cell: ({ row }) => renderComponent(DateCell, { iso: row.original.match_date }), | |
| enableGlobalFilter: false, | |
| meta: { label: 'Date' } | |
| }, | |
| uploadedColumn<RoundRow>() | |
| ]; | |
| export const mapColumns: ColumnDef<MapRow>[] = [ | |
| matchIdColumn<MapRow>(), | |
| eventColumn<MapRow>(), | |
| { | |
| id: 'map_name', | |
| accessorKey: 'map_name', | |
| header: () => renderComponent(PlainHeader, { label: 'Map' }), | |
| cell: ({ row }) => renderComponent(MapCell, { map: row.original.map_name }), | |
| enableSorting: false, | |
| filterFn: (row, id, value) => { | |
| if (!value) return true; | |
| return row.getValue<string>(id) === value; | |
| }, | |
| meta: { label: 'Map' } | |
| }, | |
| { | |
| id: 'teams', | |
| accessorFn: (r) => `${r.team1} ${r.team2}`, | |
| header: () => renderComponent(PlainHeader, { label: 'Teams' }), | |
| cell: ({ row }) => | |
| renderComponent(TeamsCell, { | |
| team1: row.original.team1, | |
| team2: row.original.team2, | |
| winner: row.original.winner | |
| }), | |
| enableSorting: false, | |
| meta: { label: 'Teams' } | |
| }, | |
| { | |
| id: 'score', | |
| accessorFn: (r) => r.score1 + r.score2, | |
| header: ({ column }) => renderComponent(SortHeader, { column, label: 'Score', align: 'start' }), | |
| cell: ({ row }) => | |
| renderComponent(ScoreCell, { | |
| score1: row.original.score1, | |
| score2: row.original.score2, | |
| winner: row.original.winner | |
| }), | |
| enableGlobalFilter: false, | |
| meta: { label: 'Score' } | |
| }, | |
| { | |
| id: 'winner_side', | |
| accessorKey: 'winner_side', | |
| header: () => renderComponent(PlainHeader, { label: 'Won by' }), | |
| cell: ({ row }) => | |
| renderComponent(WinnerSideCell, { side: (row.original as Match).winner_side }), | |
| enableSorting: false, | |
| filterFn: (row, id, value) => { | |
| if (!value) return true; | |
| return ((row.getValue<string>(id) ?? '') + '').toLowerCase() === value; | |
| }, | |
| meta: { label: 'Won by' } | |
| }, | |
| { | |
| id: 'rounds_played', | |
| accessorKey: 'rounds_played', | |
| header: ({ column }) => renderComponent(SortHeader, { column, label: 'Rounds' }), | |
| cell: ({ row }) => renderComponent(RoundsPlayedCell, { rounds: row.original.rounds_played }), | |
| enableGlobalFilter: false, | |
| meta: { label: 'Rounds' } | |
| }, | |
| { | |
| id: 'duration_s', | |
| accessorKey: 'duration_s', | |
| header: ({ column }) => renderComponent(SortHeader, { column, label: 'Duration' }), | |
| cell: ({ row }) => renderComponent(DurationCell, { seconds: row.original.duration_s }), | |
| enableGlobalFilter: false, | |
| meta: { label: 'Duration' } | |
| }, | |
| { | |
| id: 'match_date', | |
| accessorFn: (r) => new Date(r.match_date).getTime(), | |
| sortingFn: (a, b) => dateSort(a.original, b.original), | |
| header: ({ column }) => renderComponent(SortHeader, { column, label: 'Date' }), | |
| cell: ({ row }) => renderComponent(DateCell, { iso: row.original.match_date }), | |
| enableGlobalFilter: false, | |
| meta: { label: 'Date' } | |
| }, | |
| uploadedColumn<MapRow>() | |
| ]; | |
| export const povColumns: ColumnDef<PovRow>[] = [ | |
| matchIdColumn<PovRow>(), | |
| eventColumn<PovRow>(), | |
| { | |
| id: 'map_name', | |
| accessorKey: 'map_name', | |
| header: () => renderComponent(PlainHeader, { label: 'Map' }), | |
| cell: ({ row }) => renderComponent(MapCell, { map: row.original.map_name }), | |
| enableSorting: false, | |
| filterFn: (row, id, value) => { | |
| if (!value) return true; | |
| return row.getValue<string>(id) === value; | |
| }, | |
| meta: { label: 'Map' } | |
| }, | |
| { | |
| id: 'round', | |
| accessorKey: 'round', | |
| header: ({ column }) => renderComponent(SortHeader, { column, label: 'Round' }), | |
| cell: ({ row }) => | |
| renderComponent(RoundCell, { round: row.original.round, total: row.original.rounds_played }), | |
| enableGlobalFilter: false, | |
| meta: { label: 'Round' } | |
| }, | |
| { | |
| id: 'player', | |
| accessorKey: 'player', | |
| header: ({ column }) => renderComponent(SortHeader, { column, label: 'POV' }), | |
| cell: ({ row }) => renderComponent(PlayerCell, { player: row.original.player }), | |
| enableGlobalFilter: false, | |
| meta: { label: 'POV' } | |
| }, | |
| { | |
| id: 'start_t', | |
| accessorKey: 'start_t', | |
| header: ({ column }) => renderComponent(SortHeader, { column, label: 'Start' }), | |
| cell: ({ row }) => renderComponent(StartTimeCell, { seconds: row.original.start_t }), | |
| enableGlobalFilter: false, | |
| meta: { label: 'Start' } | |
| }, | |
| { | |
| id: 'teams', | |
| accessorFn: (r) => `${r.team1} ${r.team2}`, | |
| header: () => renderComponent(PlainHeader, { label: 'Teams' }), | |
| cell: ({ row }) => | |
| renderComponent(TeamsCell, { | |
| team1: row.original.team1, | |
| team2: row.original.team2, | |
| winner: row.original.winner | |
| }), | |
| enableSorting: false, | |
| meta: { label: 'Teams' } | |
| }, | |
| { | |
| id: 'duration_s', | |
| accessorKey: 'duration_s', | |
| header: ({ column }) => renderComponent(SortHeader, { column, label: 'Duration' }), | |
| cell: ({ row }) => renderComponent(DurationCell, { seconds: row.original.duration_s }), | |
| enableGlobalFilter: false, | |
| meta: { label: 'Duration' } | |
| }, | |
| { | |
| id: 'match_date', | |
| accessorFn: (r) => new Date(r.match_date).getTime(), | |
| sortingFn: (a, b) => dateSort(a.original, b.original), | |
| header: ({ column }) => renderComponent(SortHeader, { column, label: 'Date' }), | |
| cell: ({ row }) => renderComponent(DateCell, { iso: row.original.match_date }), | |
| enableGlobalFilter: false, | |
| meta: { label: 'Date' } | |
| }, | |
| uploadedColumn<PovRow>() | |
| ]; | |
| export const matchColumns: ColumnDef<MatchRow>[] = [ | |
| matchIdColumn<MatchRow>(), | |
| eventColumn<MatchRow>(), | |
| { | |
| id: 'teams', | |
| accessorFn: (r) => `${r.team1} ${r.team2}`, | |
| header: () => renderComponent(PlainHeader, { label: 'Teams' }), | |
| cell: ({ row }) => | |
| renderComponent(TeamsCell, { | |
| team1: row.original.team1, | |
| team2: row.original.team2, | |
| winner: row.original.winner | |
| }), | |
| enableSorting: false, | |
| meta: { label: 'Teams' } | |
| }, | |
| { | |
| id: 'score', | |
| accessorFn: (r) => r.score1 + r.score2, | |
| header: ({ column }) => renderComponent(SortHeader, { column, label: 'Maps' }), | |
| cell: ({ row }) => | |
| renderComponent(ScoreCell, { | |
| score1: row.original.score1, | |
| score2: row.original.score2, | |
| winner: row.original.winner | |
| }), | |
| enableGlobalFilter: false, | |
| meta: { label: 'Maps won' } | |
| }, | |
| { | |
| id: 'maps', | |
| accessorFn: (r) => r.maps.join(' '), | |
| header: () => renderComponent(PlainHeader, { label: 'Map pool' }), | |
| cell: ({ row }) => renderComponent(MapsListCell, { maps: row.original.maps }), | |
| enableSorting: false, | |
| meta: { label: 'Map pool' } | |
| }, | |
| { | |
| id: 'rounds_played', | |
| accessorKey: 'rounds_played', | |
| header: ({ column }) => renderComponent(SortHeader, { column, label: 'Rounds' }), | |
| cell: ({ row }) => renderComponent(RoundsPlayedCell, { rounds: row.original.rounds_played }), | |
| enableGlobalFilter: false, | |
| meta: { label: 'Rounds' } | |
| }, | |
| { | |
| id: 'duration_s', | |
| accessorKey: 'duration_s', | |
| header: ({ column }) => renderComponent(SortHeader, { column, label: 'Duration' }), | |
| cell: ({ row }) => renderComponent(DurationCell, { seconds: row.original.duration_s }), | |
| enableGlobalFilter: false, | |
| meta: { label: 'Duration' } | |
| }, | |
| { | |
| id: 'match_date', | |
| accessorFn: (r) => new Date(r.match_date).getTime(), | |
| sortingFn: (a, b) => dateSort(a.original, b.original), | |
| header: ({ column }) => renderComponent(SortHeader, { column, label: 'Date' }), | |
| cell: ({ row }) => renderComponent(DateCell, { iso: row.original.match_date }), | |
| enableGlobalFilter: false, | |
| meta: { label: 'Date' } | |
| }, | |
| uploadedColumn<MatchRow>() | |
| ]; | |