soiz1's picture
Upload 2891 files
6bcb42f verified
import {FormattedMessage, intlShape, defineMessages} from 'react-intl';
import PropTypes from 'prop-types';
import React from 'react';
import Box from '../box/box.jsx';
import PlayButton from '../../containers/play-button.jsx';
import styles from './library-item.css';
import classNames from 'classnames';
import bluetoothIconURL from './bluetooth.svg';
import internetConnectionIconURL from './internet-connection.svg';
import favoritedFilledUrl from './favorite/filled.svg';
import favoritedOutlineUrl from './favorite/outline.svg';
import deleteFilledUrl from './delete/filled.svg';
import downloadFilled from './download/filled.svg';
const getURLOrigin = (url) => {
let urlObj;
try {
urlObj = new URL(url);
} catch {
// not a valid URL
return String(url);
}
return urlObj.origin;
};
const getMSFormatted = (ms) => {
return (ms / 1000).toFixed(2);
};
/* eslint-disable react/prefer-stateless-function */
class LibraryItemComponent extends React.PureComponent {
render() {
return this.props.featured ? (
<div
className={classNames(
styles.libraryItem,
styles.featuredItem,
{
[styles.disabled]: this.props.disabled
},
typeof this.props.extensionId === 'string' ? styles.libraryItemExtension : null,
this.props.hidden ? styles.hidden : null
)}
onClick={this.props.onClick}
>
<div className={styles.featuredImageContainer}>
{this.props.disabled ? (
<div className={styles.comingSoonText}>
<FormattedMessage
defaultMessage="Coming Soon"
description="Label for extensions that are not yet implemented"
id="gui.extensionLibrary.comingSoon"
/>
</div>
) : null}
<img
className={styles.featuredImage}
loading="lazy"
draggable={false}
src={this.props.iconURL}
/>
</div>
{(this.props.insetIconURL && !this.props.customInsetColor) ? (
<div className={
this.props.twDeveloper ?
classNames(styles.libraryItemInsetImageContainer, styles.twLibraryItemInsetImageContainer)
: styles.libraryItemInsetImageContainer
}
>
<img
className={styles.libraryItemInsetImage}
src={this.props.insetIconURL}
draggable={false}
/>
</div>
) : null}
{(this.props.insetIconURL && this.props.customInsetColor) ? (
<div className={
styles.libraryItemInsetImageContainerNoBg
}
style={{ backgroundColor: this.props.customInsetColor }}
>
<img
className={styles.libraryItemInsetImage}
src={this.props.insetIconURL}
/>
</div>
) : null}
{(this.props.favoritable && !this.props.deletable) ? (
<button
// data-clearclick just makes it so the item
// doesnt get selected when clicking this element
data-clearclick="true"
data-activated={this.props.favorited === true}
className={styles.libraryItemFavorite}
onClick={() => this.props.onFavoriteClick(this.props.favorited)}
>
{this.props.favorited === true ? (
<img
data-usedimage="true"
data-clearclick="true"
src={favoritedFilledUrl}
/>
) : (
<img
data-usedimage="true"
data-clearclick="true"
src={favoritedOutlineUrl}
/>
)}
<img
data-usedimage="false"
data-clearclick="true"
src={favoritedFilledUrl}
/>
</button>
) : null}
{this.props.deletable && (
<button
// data-clearclick just makes it so the item
// doesnt get selected when clicking this element
data-clearclick="true"
className={styles.libraryItemDelete}
onClick={this.props.onDeleteClick}
>
<img
data-clearclick="true"
src={deleteFilledUrl}
/>
</button>
)}
<div
className={typeof this.props.extensionId === 'string' ?
classNames(styles.featuredExtensionText, styles.featuredText) : styles.featuredText
}
>
<span className={styles.libraryItemName}>{this.props.name}</span>
<br />
<span className={styles.featuredDescription}>{this.props.description}</span>
{this.props.custom && (
<>
<br />
{this.props.extensionId.startsWith("data:") ? (
<span>
{this.props._unsandboxed ?
(
<FormattedMessage
defaultMessage="Custom Unsandboxed extension"
description="Label for custom library extensions that are unsandboxed (not safe)"
id="pm.extensionLibrary.customLibraryExtensionUnsandboxed"
/>
) : (
<FormattedMessage
defaultMessage="Custom Sandboxed extension"
description="Label for custom library extensions that are sandboxed"
id="pm.extensionLibrary.customLibraryExtensionSandboxed"
/>
)}
</span>
) : (
<span>
<FormattedMessage
defaultMessage="Added from a website"
description="Label for custom library extensions that are added from a URL"
id="pm.extensionLibrary.customLibraryExtensionWebsite"
/>
</span>
)}
{this.props.extensionId.startsWith("data:") ? (
<span className={styles.featuredDescription}>
<FormattedMessage
defaultMessage="Loaded from Text / File"
description="Label for custom library extensions that are added from text or a file"
id="pm.extensionLibrary.customLibraryExtensionTextOrFile"
/>
<a
data-clearclick="true"
download="extension.js"
href={this.props.extensionId}
>
<button
data-clearclick="true"
className={styles.inspectExtension}
>
<img
data-clearclick="true"
src={downloadFilled}
alt="Download"
/>
</button>
</a>
</span>
) : (
<a
target='_blank'
data-clearclick="true"
href={this.props.extensionId}
className={styles.featuredDescription}
>
{getURLOrigin(this.props.extensionId)}
</a>
)}
</>
)}
</div>
{
this.props.bluetoothRequired ||
this.props.internetConnectionRequired ||
this.props.collaborator ||
this.props.extDeveloper ||
this.props.twDeveloper ||
this.props.eventSubmittor ||
this.props.credits
? (
<div className={styles.featuredExtensionMetadata}>
<div className={styles.featuredExtensionRequirement}>
{this.props.bluetoothRequired || this.props.internetConnectionRequired ? (
<div>
<div>
<FormattedMessage
defaultMessage="Requires"
description="Label for extension hardware requirements"
id="gui.extensionLibrary.requires"
/>
</div>
<div
className={styles.featuredExtensionMetadataDetail}
>
{this.props.bluetoothRequired ? (
<img src={bluetoothIconURL} />
) : null}
{this.props.internetConnectionRequired ? (
<img src={internetConnectionIconURL} />
) : null}
</div>
</div>
) : null}
</div>
<div className={styles.featuredExtensionCollaboration}>
{this.props.collaborator ? (
<div className={styles.smallBottomMargin}>
<div>
<FormattedMessage
defaultMessage="Collaboration with"
description="Label for extension collaboration"
id="gui.extensionLibrary.collaboration"
/>
</div>
<div
className={styles.featuredExtensionMetadataDetail}
>
{this.props.collaborator}
</div>
</div>
) : null}
{this.props.twDeveloper ? (
<div className={styles.smallBottomMargin}>
<div>
Originally for TurboWarp by
</div>
<div
className={styles.featuredExtensionMetadataDetail}
>
{this.props.twDeveloper}
</div>
</div>
) : null}
{this.props.extDeveloper ? (
<div className={styles.smallBottomMargin}>
<div>
Created by
</div>
<div
className={styles.featuredExtensionMetadataDetail}
>
{this.props.extDeveloper}
</div>
</div>
) : null}
{this.props.eventSubmittor ? (
<div className={styles.smallBottomMargin}>
<div>
Event Submission by
</div>
<div
className={styles.featuredExtensionMetadataDetail}
>
{this.props.eventSubmittor}
</div>
</div>
) : null}
{this.props.credits ? (
<div className={styles.smallBottomMargin}>
<div>
Credits
</div>
<div
className={styles.featuredExtensionMetadataDetail}
>
{this.props.credits}
</div>
</div>
) : null}
</div>
</div>
) : null}
</div>
) : (
<Box
className={classNames(
styles.libraryItem, {
[styles.hidden]: this.props.hidden,
[styles.libraryItemSound]: this.props.styleForSound,
[styles.libraryItemNew]: this.props.isNew,
}
)}
role="button"
tabIndex="0"
onBlur={this.props.onBlur}
onClick={this.props.onClick}
onFocus={this.props.onFocus}
onKeyPress={this.props.onKeyPress}
onMouseEnter={this.props.showPlayButton ? null : this.props.onMouseEnter}
onMouseLeave={this.props.showPlayButton ? null : this.props.onMouseLeave}
>
{this.props.isNew && (
<div className={styles.libraryItemNewBadge}>
NEW
</div>
)}
{/* Layers of wrapping is to prevent layout thrashing on animation */}
<Box className={styles.libraryItemImageContainerWrapper}>
<Box
className={styles.libraryItemImageContainer}
onMouseEnter={this.props.showPlayButton ? this.props.onMouseEnter : null}
onMouseLeave={this.props.showPlayButton ? this.props.onMouseLeave : null}
>
<img
className={classNames(
styles.libraryItemImage, {
[styles.libraryItemWaveform]: this.props.styleForSound
}
)}
loading="lazy"
src={this.props.iconURL}
draggable={false}
/>
{this.props.overlayURL && (
<img
className={classNames(
styles.libraryItemImage, styles.libraryItemImageOverlay, {
[styles.libraryItemWaveform]: this.props.styleForSound
}
)}
loading="lazy"
src={this.props.overlayURL}
draggable={false}
/>
)}
</Box>
</Box>
{this.props.styleForSound ? (
<div className={styles.libraryItemSoundInfoContainer}>
<span className={classNames(styles.libraryItemName, styles.libraryItemSoundName)}>{this.props.name}</span>
<span className={classNames(styles.libraryItemName, styles.libraryItemSoundType)}>
{this.props.soundType}, {getMSFormatted(this.props.soundLength)}
</span>
</div>
) : (
<span className={styles.libraryItemName}>{this.props.name}</span>
)}
{this.props.showPlayButton ? (
<PlayButton
className={classNames({
[styles.libraryItemSoundPlayButton]: this.props.styleForSound,
[styles.libraryItemNewPlayButton]: this.props.isNew,
})}
isPlaying={this.props.isPlaying}
onPlay={this.props.onPlay}
onStop={this.props.onStop}
/>
) : null}
</Box>
);
}
}
/* eslint-enable react/prefer-stateless-function */
LibraryItemComponent.propTypes = {
intl: intlShape,
bluetoothRequired: PropTypes.bool,
collaborator: PropTypes.string,
credits: PropTypes.string,
twDeveloper: PropTypes.string,
extDeveloper: PropTypes.string,
eventSubmittor: PropTypes.string,
description: PropTypes.oneOfType([
PropTypes.string,
PropTypes.node
]),
disabled: PropTypes.bool,
extensionId: PropTypes.string,
featured: PropTypes.bool,
isNew: PropTypes.bool,
hidden: PropTypes.bool,
iconURL: PropTypes.string,
overlayURL: PropTypes.string,
insetIconURL: PropTypes.string,
styleForSound: PropTypes.bool,
soundType: PropTypes.string,
soundLength: PropTypes.number,
customInsetColor: PropTypes.string,
internetConnectionRequired: PropTypes.bool,
isPlaying: PropTypes.bool,
name: PropTypes.oneOfType([
PropTypes.string,
PropTypes.node
]),
onBlur: PropTypes.func.isRequired,
onClick: PropTypes.func.isRequired,
onFocus: PropTypes.func.isRequired,
onKeyPress: PropTypes.func.isRequired,
onMouseEnter: PropTypes.func.isRequired,
onMouseLeave: PropTypes.func.isRequired,
onPlay: PropTypes.func.isRequired,
onStop: PropTypes.func.isRequired,
showPlayButton: PropTypes.bool,
favoritable: PropTypes.bool,
favorited: PropTypes.bool,
deletable: PropTypes.bool,
custom: PropTypes.bool,
onFavoriteClick: PropTypes.func,
onDeleteClick: PropTypes.func,
_id: PropTypes.string,
_unsandboxed: PropTypes.bool
};
LibraryItemComponent.defaultProps = {
disabled: false,
showPlayButton: false
};
export default LibraryItemComponent;