168 lines
5.3 KiB
TypeScript
168 lines
5.3 KiB
TypeScript
/**
|
|
* Copyright (C) 2019-2021 Carl Kittelberger <icedream@icedream.pw>
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as
|
|
* published by the Free Software Foundation, either version 3 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Affero General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
import React, { ReactElement } from 'react';
|
|
|
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
|
|
import ListGroup from 'react-bootstrap/ListGroup';
|
|
import Image from 'react-bootstrap/Image';
|
|
|
|
import Link from 'next/link';
|
|
|
|
import { RunInformation, Thumbnails } from 'util/datatypes/VideoList';
|
|
import { Runner as RunnerData, RunnerList } from 'util/datatypes/RunnerList';
|
|
import { Col, Row } from 'react-bootstrap';
|
|
import { faClock, faHourglass, faRunning } from '@fortawesome/free-solid-svg-icons';
|
|
import { getThumbnailURL } from '../util/thumbnail';
|
|
|
|
import FormattedDuration from './localization/FormattedDuration';
|
|
|
|
import style from './VideoListItem.module.scss';
|
|
|
|
import hourglassImage from '../images/hourglass.svg';
|
|
import Runner from './Runner';
|
|
|
|
export default function VideoListItem({
|
|
thumbnailServerURL,
|
|
duration,
|
|
id,
|
|
slug,
|
|
title,
|
|
sourceVideoStart,
|
|
sourceVideoEnd,
|
|
runData,
|
|
runners,
|
|
thumbnails,
|
|
}: {
|
|
thumbnailServerURL: string,
|
|
duration: number | string,
|
|
id: string,
|
|
slug: string,
|
|
title: string,
|
|
sourceVideoStart: number | string,
|
|
sourceVideoEnd: number | string,
|
|
runData: RunInformation,
|
|
runners: RunnerList,
|
|
thumbnails: Thumbnails,
|
|
}) {
|
|
let displayDuration = null;
|
|
if (duration !== null) {
|
|
if (typeof duration === 'string') {
|
|
displayDuration = parseFloat(duration);
|
|
} else {
|
|
displayDuration = duration;
|
|
}
|
|
} else if (
|
|
sourceVideoStart !== null
|
|
&& sourceVideoEnd !== null
|
|
&& sourceVideoStart !== sourceVideoEnd
|
|
) {
|
|
let videoEnd: number;
|
|
if (typeof sourceVideoEnd === 'string') {
|
|
videoEnd = parseFloat(sourceVideoEnd);
|
|
} else {
|
|
videoEnd = sourceVideoEnd;
|
|
}
|
|
let videoStart: number;
|
|
if (typeof sourceVideoStart === 'string') {
|
|
videoStart = parseFloat(sourceVideoStart);
|
|
} else {
|
|
videoStart = sourceVideoStart;
|
|
}
|
|
displayDuration = videoEnd - videoStart;
|
|
}
|
|
const listGroupItem = (
|
|
<ListGroup.Item>
|
|
<Row>
|
|
<Col sm={3} xs={3}>
|
|
<Link href="/[id]/[vslug]" as={`/${id}/${slug}`}>
|
|
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
|
|
<Image
|
|
className={style.thumbnail}
|
|
src={
|
|
thumbnails.length > 0
|
|
? getThumbnailURL(thumbnailServerURL, id, thumbnails[0].fileName)
|
|
: hourglassImage
|
|
}
|
|
srcSet={
|
|
Array.isArray(thumbnails) && thumbnails.length > 0
|
|
? thumbnails
|
|
.map(({
|
|
sourceSize,
|
|
fileName,
|
|
}) => (
|
|
[
|
|
thumbnails.length > 0
|
|
? getThumbnailURL(thumbnailServerURL, id, fileName)
|
|
: hourglassImage,
|
|
sourceSize,
|
|
]
|
|
))
|
|
.map((item) => item.join(' '))
|
|
.join(', ')
|
|
: ''
|
|
}
|
|
alt={title}
|
|
/>
|
|
</Link>
|
|
</Col>
|
|
<Col sm={4} xs={9}>
|
|
<Link href="/[id]/[vslug]" as={`/${id}/${slug}`} className="text-reset text-decoration-none">
|
|
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
|
|
<div>
|
|
<div className={style['run-name']}>{title}</div>
|
|
<div className={[style['run-category'], 'mt-0'].join(' ')}>{runData?.category}</div>
|
|
</div>
|
|
</Link>
|
|
</Col>
|
|
<Col sm={5} xs={12}>
|
|
{runners && runners.length > 0 ? (
|
|
<div className="mr-2">
|
|
<FontAwesomeIcon icon={faRunning} />
|
|
{' '}
|
|
{runners.reduce((all: Array<ReactElement>, runner: RunnerData) => [
|
|
...all,
|
|
all.length > 0 ? ' / ' : null,
|
|
<Runner key={runner.fields.name} runner={runner.fields} />,
|
|
], [])}
|
|
</div>
|
|
) : ''}
|
|
{displayDuration !== null ? (
|
|
<span className="mr-2 text-nowrap">
|
|
<FontAwesomeIcon icon={faClock} />
|
|
{' '}
|
|
<FormattedDuration
|
|
seconds={displayDuration}
|
|
format="{hours} {minutes} {seconds}"
|
|
unitDisplay="short"
|
|
/>
|
|
</span>
|
|
) : (
|
|
<span className="mr-2 text-nowrap">
|
|
<FontAwesomeIcon icon={faHourglass} />
|
|
{' '}
|
|
Coming up
|
|
</span>
|
|
)}
|
|
</Col>
|
|
</Row>
|
|
</ListGroup.Item>
|
|
);
|
|
return listGroupItem;
|
|
}
|