Add files via upload
This commit is contained in:
parent
0feb8b6b4f
commit
6885275f42
|
@ -21,7 +21,8 @@
|
|||
"description": { "default": "Soccer Hightlights Web Parts show latest hightlights from around the world." },
|
||||
"officeFabricIconFontName": "Soccer",
|
||||
"properties": {
|
||||
"tile": "Soocer Highlights"
|
||||
"title": "Soccer Highlights",
|
||||
"pageSize": 5
|
||||
}
|
||||
}]
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import {
|
|||
IPropertyPaneConfiguration,
|
||||
PropertyPaneTextField,
|
||||
PropertyPaneSlider,
|
||||
PropertyPaneToggle,
|
||||
} from '@microsoft/sp-property-pane';
|
||||
import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base';
|
||||
|
||||
|
@ -18,6 +19,7 @@ export interface IReactSpFxWebPartProps {
|
|||
title: string;
|
||||
pageSize: number;
|
||||
displayMode: DisplayMode;
|
||||
showFlatMode: boolean;
|
||||
updateProperty: (value: string) => void;
|
||||
}
|
||||
|
||||
|
@ -29,7 +31,8 @@ export default class ReactSpFxWebPart extends BaseClientSideWebPart<IReactSpFxWe
|
|||
{
|
||||
title: this.properties.title,
|
||||
displayMode: this.properties.displayMode,
|
||||
pageSize: this.properties.pageSize,
|
||||
pageSize: this.properties.pageSize == undefined ? 10 : this.properties.pageSize,
|
||||
showFlatMode: this.properties.showFlatMode,
|
||||
updateProperty: (value: string) => {this.properties.title = value;},
|
||||
onConfigure: () => {
|
||||
this.context.propertyPane.open();
|
||||
|
@ -66,10 +69,14 @@ export default class ReactSpFxWebPart extends BaseClientSideWebPart<IReactSpFxWe
|
|||
label:"Highlights Per Page",
|
||||
min:1,
|
||||
max:20,
|
||||
value:2,
|
||||
value:5,
|
||||
showValue:true,
|
||||
step:1
|
||||
})
|
||||
}),
|
||||
PropertyPaneToggle('showFlatMode', {
|
||||
label: "Show Videos in Flat Mode",
|
||||
checked: false
|
||||
})
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
|
@ -5,11 +5,12 @@ export interface IReactSpFxProps {
|
|||
title: string;
|
||||
displayMode: DisplayMode;
|
||||
pageSize: number;
|
||||
showFlatMode: boolean;
|
||||
updateProperty: (value: string) => void;
|
||||
onConfigure: () => void;
|
||||
}
|
||||
|
||||
export interface IVidesList {
|
||||
export interface IVideosList {
|
||||
videos: IVideo[];
|
||||
}
|
||||
|
||||
|
@ -19,18 +20,16 @@ export interface IVideo {
|
|||
}
|
||||
|
||||
export interface ISportsHighlightsState {
|
||||
sportHighlightState: [];
|
||||
sportHighlightState: any;
|
||||
}
|
||||
export interface ISportsHighlightPagingState {
|
||||
currentPage: number;
|
||||
indexOfLastHighlight: number;
|
||||
indexOfFirstHighlight: number;
|
||||
highLightsPerPage: number;
|
||||
pagedSportHighlights?: ISportsHighlightProps[];
|
||||
slicedSportHighlights?: ISportsHighlightProps[];
|
||||
}
|
||||
|
||||
export interface ISportsHightLightsProps {
|
||||
pageSize:number;
|
||||
sportsHighlights: [];
|
||||
showFlatMode: boolean;
|
||||
}
|
||||
|
||||
export interface ISide {
|
||||
|
@ -41,8 +40,13 @@ export interface ICompetition{
|
|||
id: number;
|
||||
}
|
||||
|
||||
export interface ISportsHighlights {
|
||||
highLights?: ISportsHighlightProps[];
|
||||
}
|
||||
|
||||
export interface ISportsHighlightProps {
|
||||
title: string;
|
||||
embed: string
|
||||
id: string;
|
||||
date: Date;
|
||||
side1: ISide;
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
border: 1px solid lightblue;
|
||||
height: 100px;
|
||||
padding: 10px 0;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
|
|
@ -6,35 +6,18 @@ import SportsHighlightsList from "./SportsHighlightsList";
|
|||
import { WebPartTitle } from "@pnp/spfx-controls-react/lib/WebPartTitle";
|
||||
import { Placeholder } from "@pnp/spfx-controls-react/lib/Placeholder";
|
||||
|
||||
import axios from "axios";
|
||||
|
||||
import { setVirtualParent } from "office-ui-fabric-react";
|
||||
import SportsHighlights from "./SportsHighlightsList";
|
||||
import "bootstrap/dist/css/bootstrap.css";
|
||||
|
||||
export default class ReactSpFx extends React.Component<
|
||||
IReactSpFxProps,
|
||||
ISportsHighlightsState
|
||||
> {
|
||||
export default class ReactSpFx extends React.Component<IReactSpFxProps> {
|
||||
public constructor(props: IReactSpFxProps, state: ISportsHighlightsState) {
|
||||
super(props);
|
||||
this.state = {
|
||||
sportHighlightState: [],
|
||||
};
|
||||
}
|
||||
|
||||
GetData = async () => {
|
||||
const resp = await axios.get(`https://www.scorebat.com/video-api/v1/`);
|
||||
const data = await resp.data;
|
||||
this.setState({ sportHighlightState: data });
|
||||
};
|
||||
|
||||
async componentDidMount() {
|
||||
this.GetData();
|
||||
}
|
||||
|
||||
public render(): React.ReactElement<IReactSpFxProps> {
|
||||
const globalComponent = this;
|
||||
console.log(this.props.pageSize);
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
{!this.props.title && (
|
||||
|
@ -56,9 +39,7 @@ export default class ReactSpFx extends React.Component<
|
|||
</div>
|
||||
)}
|
||||
<span></span>
|
||||
<SportsHighlightsList
|
||||
sportsHighlights={this.state.sportHighlightState}
|
||||
pageSize={this.props.pageSize}
|
||||
<SportsHighlightsList pageSize={this.props.pageSize} showFlatMode={this.props.showFlatMode}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import { ISportsHighlightProps, ISportsHighlights } from "./IReactSpFxProps";
|
||||
import SportsVideo from "./SportsVideo";
|
||||
import ReactMarkdownWithHtml from "react-markdown/with-html";
|
||||
import { FilmstripLayout } from './filmstripLayout/index';
|
||||
import styles from './filmstripLayout/FilmstripLayout.module.scss';
|
||||
|
||||
import {
|
||||
DocumentCard,
|
||||
DocumentCardActivity,
|
||||
DocumentCardPreview,
|
||||
DocumentCardDetails,
|
||||
DocumentCardTitle,
|
||||
IDocumentCardPreviewProps,
|
||||
DocumentCardLocation,
|
||||
DocumentCardType,
|
||||
} from "office-ui-fabric-react/lib/DocumentCard";
|
||||
|
||||
import { ImageFit } from "office-ui-fabric-react/lib/Image";
|
||||
export interface IDialogState
|
||||
{
|
||||
isDialogOpen: boolean;
|
||||
}
|
||||
export default class SportVideoListFilmStripView extends React.Component<
|
||||
ISportsHighlights,
|
||||
IDialogState
|
||||
> {
|
||||
constructor(props: ISportsHighlights, state: IDialogState) {
|
||||
super(props);
|
||||
this.state = {
|
||||
isDialogOpen: false,
|
||||
};
|
||||
}
|
||||
openDialog = (video: ISportsHighlightProps) => {
|
||||
console.log("I awas clicked:" + video.title);
|
||||
this.setState({ isDialogOpen: true });
|
||||
};
|
||||
handleClose = () => this.setState({ isDialogOpen: false });
|
||||
|
||||
public render(): React.ReactElement<ISportsHighlights> {
|
||||
const videos = this.props.highLights;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={styles.filmStrip}>
|
||||
<FilmstripLayout
|
||||
ariaLabel={
|
||||
"Sample filmstrip layout web part, showing sample items., Use right and left arrow keys to navigate between cards in the film strip."
|
||||
}
|
||||
>
|
||||
{this.props.highLights.map((video: ISportsHighlightProps, i) => {
|
||||
let videoDate = new Date(video.date.toString());
|
||||
const previewProps: IDocumentCardPreviewProps = {
|
||||
previewImages: [
|
||||
{
|
||||
previewImageSrc: video.thumbnail,
|
||||
imageFit: ImageFit.cover,
|
||||
height: 130,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
key={i}
|
||||
data-is-focusable={true}
|
||||
role="listitem"
|
||||
aria-label={video.title}
|
||||
>
|
||||
<DocumentCard
|
||||
type={DocumentCardType.normal}
|
||||
onClick={(ev: React.SyntheticEvent<HTMLElement>) =>
|
||||
this.openDialog(video)
|
||||
}
|
||||
>
|
||||
{/* <DocumentCardPreview {...previewProps} /> */}
|
||||
<DocumentCardDetails>
|
||||
{/* <DocumentCardTitle
|
||||
title={video.title}
|
||||
shouldTruncate={false}
|
||||
/> */}
|
||||
<div
|
||||
id={"video" + video.title}
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: video.embed,
|
||||
}}
|
||||
style={{ width: 268, padding: "2px" }}
|
||||
title={"click to play " + video.title}
|
||||
/>
|
||||
<DocumentCardActivity
|
||||
activity={
|
||||
videoDate.toLocaleString()
|
||||
}
|
||||
people={[
|
||||
{
|
||||
name: video.competition.name,
|
||||
profileImageSrc: video.thumbnail,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</DocumentCardDetails>
|
||||
</DocumentCard>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</FilmstripLayout>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -3,90 +3,103 @@ import ReactDOM from "react-dom";
|
|||
import {
|
||||
ISportsHightLightsProps,
|
||||
ISportsHighlightPagingState,
|
||||
IVideo,
|
||||
ISportsHighlightsState,
|
||||
ISportsHighlightProps,
|
||||
} from "./IReactSpFxProps";
|
||||
import SportsHighlight from "./SportsHighlight";
|
||||
//import SportsHighlight from "./SportsHighlight";
|
||||
import SportVideoListFilmStripView from "./SportVideoListFilmStripView";
|
||||
import Paging from "react-paging";
|
||||
import Pagination from "./Pagination";
|
||||
import { PrimaryButton } from 'office-ui-fabric-react/lib/Button';
|
||||
import axios from "axios";
|
||||
import SportsVideoList from "./SportsVideoList";
|
||||
|
||||
|
||||
export default class SportsHighlightsList extends React.Component<
|
||||
ISportsHightLightsProps,
|
||||
ISportsHighlightPagingState
|
||||
> {
|
||||
constructor(props) {
|
||||
constructor(
|
||||
props: ISportsHightLightsProps,
|
||||
state: ISportsHighlightPagingState
|
||||
) {
|
||||
super(props);
|
||||
this.state = {
|
||||
currentPage: 1,
|
||||
indexOfFirstHighlight: 1,
|
||||
indexOfLastHighlight: 5,
|
||||
highLightsPerPage: this.props.pageSize,
|
||||
pagedSportHighlights: [],
|
||||
slicedSportHighlights: [],
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
paginate = (page) => {
|
||||
console.clear();
|
||||
|
||||
const indexOfLastHighlight =
|
||||
this.state.currentPage * this.state.highLightsPerPage;
|
||||
const indexOfFirstHighlight =
|
||||
indexOfLastHighlight - this.state.highLightsPerPage;
|
||||
|
||||
this.setState({
|
||||
currentPage: page,
|
||||
indexOfLastHighlight: indexOfLastHighlight,
|
||||
indexOfFirstHighlight: indexOfFirstHighlight,
|
||||
});
|
||||
public GetData = async () => {
|
||||
const resp = await axios.get(`https://www.scorebat.com/video-api/v1/`);
|
||||
const data : ISportsHighlightProps[] = await resp.data;
|
||||
let slicedItems : ISportsHighlightProps[] = data.slice(0, this.props.pageSize);
|
||||
this.setState({ pagedSportHighlights: data, slicedSportHighlights: slicedItems });
|
||||
};
|
||||
|
||||
//paginate = (pageNumber) => setCurrentPage(pageNumber);
|
||||
|
||||
render(): React.ReactElement<ISportsHightLightsProps> {
|
||||
const sportsHighlights = this.props.sportsHighlights;
|
||||
var {
|
||||
currentPage,
|
||||
indexOfFirstHighlight,
|
||||
indexOfLastHighlight,
|
||||
} = this.state;
|
||||
async componentDidMount() {
|
||||
console.log("Mounted");
|
||||
this.GetData();
|
||||
}
|
||||
|
||||
|
||||
if (typeof indexOfFirstHighlight === "undefined" || indexOfFirstHighlight == 0)
|
||||
{
|
||||
indexOfFirstHighlight=1
|
||||
}
|
||||
|
||||
if (
|
||||
typeof indexOfFirstHighlight === "undefined" ||
|
||||
indexOfFirstHighlight == 0
|
||||
) {
|
||||
indexOfFirstHighlight = 1;
|
||||
}
|
||||
const CurrentsportsHighlights = this.props.sportsHighlights.slice(
|
||||
indexOfFirstHighlight,
|
||||
indexOfLastHighlight
|
||||
|
||||
public render(): React.ReactElement<ISportsHightLightsProps> {
|
||||
|
||||
let pageCountDivisor: number = this.props.pageSize;
|
||||
let pageCount: number;
|
||||
let pageButtons = [];
|
||||
let highlightItems = this.state.pagedSportHighlights;
|
||||
|
||||
let _pagedButtonClick = (pageNumber: number, listData: any) => {
|
||||
let startIndex: number = (pageNumber - 1) * pageCountDivisor;
|
||||
let endIndex = startIndex + pageCountDivisor;
|
||||
let listItemsCollection = [...listData];
|
||||
let slicedItems: ISportsHighlightProps[] = listItemsCollection.slice(
|
||||
startIndex,
|
||||
endIndex
|
||||
);
|
||||
this.setState({
|
||||
slicedSportHighlights: slicedItems
|
||||
});
|
||||
};
|
||||
|
||||
console.clear();
|
||||
console.log("indexOfFirstHighlight:" + indexOfFirstHighlight);
|
||||
console.log("indexOfLastHighlight : " + indexOfLastHighlight);
|
||||
console.log("currentPage :" + currentPage);
|
||||
console.log("Page Size :" + this.props.pageSize);
|
||||
// const pagedItems: JSX.Element = (
|
||||
// <SportVideoListFilmStripView highLights={this.state.slicedSportHighlights} />
|
||||
// );
|
||||
|
||||
//this.updateLastPage(currentPage);
|
||||
var pagedItems: JSX.Element = null;
|
||||
if(!this.props.showFlatMode){
|
||||
pagedItems = (<SportVideoListFilmStripView highLights={this.state.slicedSportHighlights} />);
|
||||
}
|
||||
else{
|
||||
pagedItems = (<SportsVideoList videos={this.state.slicedSportHighlights} /> );
|
||||
}
|
||||
|
||||
if (highlightItems.length > 0) {
|
||||
pageCount = Math.ceil(highlightItems.length / pageCountDivisor);
|
||||
}
|
||||
for (let i = 0; i < pageCount; i++) {
|
||||
pageButtons.push(
|
||||
<PrimaryButton key={i} style={{width:"50px"}}
|
||||
onClick={() => {
|
||||
_pagedButtonClick(i + 1, highlightItems);
|
||||
}}
|
||||
>
|
||||
{" "}
|
||||
{i + 1}{" "}
|
||||
</PrimaryButton>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="paginationDiv">
|
||||
<Pagination
|
||||
highLightsPerPage={10}
|
||||
totalHighlights={sportsHighlights.length}
|
||||
paginate={this.paginate}
|
||||
/>
|
||||
<div className={`ms-Grid-row`} style={{paddingLeft:"8px"}}>
|
||||
<div className="ms-Grid-col ms-u-lg12">{pageButtons}</div>
|
||||
</div>
|
||||
<div>
|
||||
{CurrentsportsHighlights.map((highLight, i) => (
|
||||
<SportsHighlight {...highLight} key={i} />
|
||||
))}
|
||||
<hr />
|
||||
<div className="ms-Grid-row">
|
||||
<div className="ms-Grid-col ms-u-lg12">{pagedItems}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -10,14 +10,14 @@ export default class SportsVideo extends React.Component<IVideo> {
|
|||
return (
|
||||
<div>
|
||||
<div
|
||||
style={{ fontSize: "12px", fontWeight: "bold", textAlign: "center", color:"blue" }}
|
||||
style={{ fontSize: "18px", fontWeight: "bold", textAlign: "center", color:"blue" }}
|
||||
title={"click to play " + title}
|
||||
>
|
||||
{title}
|
||||
</div>
|
||||
<div id={"video" + title}
|
||||
dangerouslySetInnerHTML={{ __html: embed }}
|
||||
style={{ width: 500, padding: "8px" }}
|
||||
style={{ padding: "8px" }}
|
||||
title={"click to play " + title}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import { IVidesList } from "./IReactSpFxProps";
|
||||
import { IVideosList } from "./IReactSpFxProps";
|
||||
import SportsVideo from "./SportsVideo";
|
||||
import ReactMarkdownWithHtml from "react-markdown/with-html";
|
||||
|
||||
export default class SportsVideoList extends React.Component<IVidesList> {
|
||||
export default class SportsVideoList extends React.Component<IVideosList> {
|
||||
public render() {
|
||||
const videos = this.props.videos;
|
||||
return (
|
||||
<div style={{ margin: "1px" }}>
|
||||
<div style={{ margin: "1px", alignContent:"center" }}>
|
||||
{this.props.videos.map((video, i) => (
|
||||
<SportsVideo
|
||||
key={i}
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
@import "~office-ui-fabric-react/dist/sass/References.scss";
|
||||
:export {
|
||||
centerPadding: 10px;
|
||||
}
|
||||
|
||||
.filmstripLayout {
|
||||
position: relative;
|
||||
|
||||
&.filmStrip {
|
||||
margin-bottom: 27px;
|
||||
margin-left: -10px;
|
||||
margin-right: -10px;
|
||||
|
||||
:global(.slick-slide) {
|
||||
box-sizing: border-box;
|
||||
padding: 0 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.sliderButtons {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
&:hover .sliderButtons {
|
||||
opacity: 1;
|
||||
|
||||
&:hover {
|
||||
color: $ms-color-white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.indexButtonContainer {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.indexButton {
|
||||
font-size: 28px;
|
||||
font-weight: 400;
|
||||
height: 40px;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
background: 0 0;
|
||||
cursor: pointer;
|
||||
color: $ms-color-white;
|
||||
width: 40px;
|
||||
min-width: 20px;
|
||||
margin-left: 0;
|
||||
line-height: 40px;
|
||||
box-sizing: content-box;
|
||||
background-color: $ms-color-black;
|
||||
opacity: 0.6;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: $ms-color-white;
|
||||
background-color: $ms-color-black;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
&:active {
|
||||
outline: -webkit-focus-ring-color auto 1px;
|
||||
}
|
||||
}
|
||||
|
||||
.carouselDotsContainer {
|
||||
.carouselDot {
|
||||
display: inline-block;
|
||||
background-color: $ms-color-black;
|
||||
height: 4px;
|
||||
width: 4px;
|
||||
opacity: 0.5;
|
||||
border: 2px solid $ms-color-black;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
opacity: 0.25;
|
||||
outline: 0;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:global(.slick-active) {
|
||||
.carouselDotsContainer {
|
||||
.carouselDot {
|
||||
background-color: "[theme:themeDark, default: #005a9e]";
|
||||
opacity: 0.75;
|
||||
border-color: "[theme:themeDark, default: #005a9e]";
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.indexButton:global(.ms-Button-flexContainer):hover:global(.ms-Icon),
|
||||
.indexButton:global(.ms-Icon:hover),
|
||||
.indexButton:hover:global(.ms-Icon) {
|
||||
color: $ms-color-white;
|
||||
}
|
||||
|
||||
.leftPositioned {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.rightPositioned {
|
||||
right: 0;
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
// This file is automatically generated.
|
||||
// Please do not change this file!
|
||||
interface CssExports {
|
||||
'carouselDot': string;
|
||||
'carouselDotsContainer': string;
|
||||
'centerPadding': string;
|
||||
'filmStrip': string;
|
||||
'filmstripLayout': string;
|
||||
'indexButton': string;
|
||||
'indexButtonContainer': string;
|
||||
'leftPositioned': string;
|
||||
'rightPositioned': string;
|
||||
'sliderButtons': string;
|
||||
}
|
||||
export const cssExports: CssExports;
|
||||
export default cssExports;
|
|
@ -0,0 +1,117 @@
|
|||
import { css } from "@uifabric/utilities/lib/css";
|
||||
import { IconButton } from "office-ui-fabric-react/lib/Button";
|
||||
import * as React from "react";
|
||||
import Slider from "react-slick";
|
||||
import { SPComponentLoader } from "@microsoft/sp-loader";
|
||||
import styles from "./FilmstripLayout.module.scss";
|
||||
import { useRef } from "react";
|
||||
import useComponentSize, { ComponentSize } from "@rehooks/component-size";
|
||||
|
||||
/**
|
||||
* Filmstrip layout
|
||||
* Presents the child compoments as a slick slide
|
||||
*/
|
||||
export const FilmstripLayout = (props: {
|
||||
children: any;
|
||||
ariaLabel?: string;
|
||||
}) => {
|
||||
let ref: React.MutableRefObject<HTMLDivElement> = useRef<HTMLDivElement>(
|
||||
null
|
||||
);
|
||||
let size: ComponentSize = useComponentSize(ref);
|
||||
let { width } = size;
|
||||
|
||||
// // the slick slider used in normal views
|
||||
let _slider: React.MutableRefObject<Slider> = useRef<Slider>(null);
|
||||
|
||||
SPComponentLoader.loadCss(
|
||||
"https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.8.1/slick.min.css"
|
||||
);
|
||||
SPComponentLoader.loadCss(
|
||||
"https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.8.1/slick-theme.min.css"
|
||||
);
|
||||
|
||||
// slick seems to have an issue with having "infinite" mode set to true and having less items than the number of slides per page
|
||||
// set infinite to true only if there are more than 3 children
|
||||
let numSlides: number = 3;
|
||||
if (width) {
|
||||
if (width > 927) {
|
||||
numSlides = 4;
|
||||
} else if (width <= 695) {
|
||||
numSlides = 2;
|
||||
}
|
||||
}
|
||||
|
||||
var isInfinite: boolean = React.Children.count(props.children) > numSlides;
|
||||
var settings: any = {
|
||||
accessibility: true,
|
||||
arrows: false,
|
||||
autoplaySpeed: 5000,
|
||||
dots: true,
|
||||
customPaging: (i: number) => {
|
||||
return (
|
||||
<a>
|
||||
<div
|
||||
role="button"
|
||||
className={styles.carouselDotsContainer}
|
||||
aria-label={`Carousel Dot ${i}`}
|
||||
data-is-focusable={true}
|
||||
tabIndex={0}
|
||||
>
|
||||
<span className={styles.carouselDot} tabIndex={-1}></span>
|
||||
</div>
|
||||
</a>
|
||||
);
|
||||
},
|
||||
infinite: isInfinite,
|
||||
slidesToShow: numSlides,
|
||||
slidesToScroll: numSlides,
|
||||
speed: 500,
|
||||
centerPadding: styles.centerPadding,
|
||||
pauseOnHover: true,
|
||||
variableWidth: false,
|
||||
useCSS: true,
|
||||
rows: 1,
|
||||
respondTo: "slider",
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div
|
||||
className={css(styles.filmstripLayout, styles.filmStrip)}
|
||||
aria-label={props.ariaLabel}
|
||||
ref={ref}
|
||||
>
|
||||
<Slider ref={_slider} {...settings}>
|
||||
{props.children}
|
||||
</Slider>
|
||||
<div
|
||||
className={css(styles.indexButtonContainer, styles.sliderButtons)}
|
||||
style={{ left: "10px" }}
|
||||
onClick={() => _slider.current.slickPrev()}
|
||||
>
|
||||
<IconButton
|
||||
className={css(styles.indexButton, styles.leftPositioned)}
|
||||
iconProps={{
|
||||
iconName: "ChevronLeft",
|
||||
styles: { root: { fontSize: "28px", fontWeight: "400" } },
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className={css(styles.indexButtonContainer, styles.sliderButtons)}
|
||||
style={{ right: "10px" }}
|
||||
onClick={() => _slider.current.slickNext()}
|
||||
>
|
||||
<IconButton
|
||||
className={css(styles.indexButton, styles.rightPositioned)}
|
||||
iconProps={{
|
||||
iconName: "ChevronRight",
|
||||
styles: { root: { fontSize: "28px", fontWeight: "400" } },
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -0,0 +1 @@
|
|||
export * from "./FilmstripLayout";
|
Loading…
Reference in New Issue