Add files via upload
This commit is contained in:
parent
c2c82059d9
commit
4df4a75818
|
@ -0,0 +1 @@
|
|||
// A file is required to be in the root of the /src directory by the TypeScript compiler
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
|
||||
"id": "0d3e8554-de4b-4b8c-bf6c-71591ffb926a",
|
||||
"alias": "ReactSpFxWebPart",
|
||||
"componentType": "WebPart",
|
||||
|
||||
// The "*" signifies that the version should be taken from the package.json
|
||||
"version": "*",
|
||||
"manifestVersion": 2,
|
||||
|
||||
// If true, the component can only be installed on sites where Custom Script is allowed.
|
||||
// Components that allow authors to embed arbitrary script code should set this to true.
|
||||
// https://support.office.com/en-us/article/Turn-scripting-capabilities-on-or-off-1f2c515f-5d7e-448a-9fd7-835da935584f
|
||||
"requiresCustomScript": false,
|
||||
"supportedHosts": ["SharePointWebPart"],
|
||||
|
||||
"preconfiguredEntries": [{
|
||||
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other
|
||||
"group": { "default": "Entertainment" },
|
||||
"title": { "default": "Soccer Hightlights" },
|
||||
"description": { "default": "Soccer Hightlights Web Parts show latest hightlights from around the world." },
|
||||
"officeFabricIconFontName": "Soccer",
|
||||
"properties": {
|
||||
"tile": "Soocer Highlights"
|
||||
}
|
||||
}]
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
import * as React from 'react';
|
||||
import * as ReactDom from 'react-dom';
|
||||
import { Version } from '@microsoft/sp-core-library';
|
||||
import {
|
||||
IPropertyPaneConfiguration,
|
||||
PropertyPaneTextField,
|
||||
PropertyPaneSlider,
|
||||
} from '@microsoft/sp-property-pane';
|
||||
import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base';
|
||||
|
||||
|
||||
import * as strings from 'ReactSpFxWebPartStrings';
|
||||
import ReactSpFx from './components/ReactSpFx';
|
||||
import { IReactSpFxProps } from './components/IReactSpFxProps';
|
||||
import { DisplayMode } from '@microsoft/sp-core-library';
|
||||
|
||||
export interface IReactSpFxWebPartProps {
|
||||
title: string;
|
||||
pageSize: number;
|
||||
displayMode: DisplayMode;
|
||||
updateProperty: (value: string) => void;
|
||||
}
|
||||
|
||||
export default class ReactSpFxWebPart extends BaseClientSideWebPart<IReactSpFxWebPartProps> {
|
||||
|
||||
public render(): void {
|
||||
const element: React.ReactElement<IReactSpFxProps> = React.createElement(
|
||||
ReactSpFx,
|
||||
{
|
||||
title: this.properties.title,
|
||||
displayMode: this.properties.displayMode,
|
||||
pageSize: this.properties.pageSize,
|
||||
updateProperty: (value: string) => {this.properties.title = value;},
|
||||
onConfigure: () => {
|
||||
this.context.propertyPane.open();
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
ReactDom.render(element, this.domElement);
|
||||
}
|
||||
|
||||
protected onDispose(): void {
|
||||
ReactDom.unmountComponentAtNode(this.domElement);
|
||||
}
|
||||
|
||||
protected get dataVersion(): Version {
|
||||
return Version.parse('1.0');
|
||||
}
|
||||
|
||||
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
|
||||
return {
|
||||
pages: [
|
||||
{
|
||||
header: {
|
||||
description: strings.PropertyPaneDescription
|
||||
},
|
||||
groups: [
|
||||
{
|
||||
groupName: strings.BasicGroupName,
|
||||
groupFields: [
|
||||
PropertyPaneTextField('title', {
|
||||
label: strings.DescriptionFieldLabel
|
||||
}),
|
||||
PropertyPaneSlider('pageSize',{
|
||||
label:"Highlights Per Page",
|
||||
min:1,
|
||||
max:20,
|
||||
value:2,
|
||||
showValue:true,
|
||||
step:1
|
||||
})
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
import { DisplayMode } from '@microsoft/sp-core-library';
|
||||
import { Placeholder } from "@pnp/spfx-controls-react/lib/Placeholder";
|
||||
|
||||
export interface IReactSpFxProps {
|
||||
title: string;
|
||||
displayMode: DisplayMode;
|
||||
pageSize: number;
|
||||
updateProperty: (value: string) => void;
|
||||
onConfigure: () => void;
|
||||
}
|
||||
|
||||
export interface IVidesList {
|
||||
videos: IVideo[];
|
||||
}
|
||||
|
||||
export interface IVideo {
|
||||
title: string;
|
||||
embed: string;
|
||||
}
|
||||
|
||||
export interface ISportsHighlightsState {
|
||||
sportHighlightState: [];
|
||||
}
|
||||
export interface ISportsHighlightPagingState {
|
||||
currentPage: number;
|
||||
indexOfLastHighlight: number;
|
||||
indexOfFirstHighlight: number;
|
||||
highLightsPerPage: number;
|
||||
}
|
||||
|
||||
export interface ISportsHightLightsProps {
|
||||
pageSize:number;
|
||||
sportsHighlights: [];
|
||||
}
|
||||
|
||||
export interface ISide {
|
||||
name: string;
|
||||
}
|
||||
export interface ICompetition{
|
||||
name: string;
|
||||
id: number;
|
||||
}
|
||||
|
||||
export interface ISportsHighlightProps {
|
||||
title: string;
|
||||
id: string;
|
||||
date: Date;
|
||||
side1: ISide;
|
||||
side2: ISide;
|
||||
competition: ICompetition;
|
||||
thumbnail: string;
|
||||
videos: IVideo[];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
import React from "react";
|
||||
|
||||
const Pagination = ({ highLightsPerPage, totalHighlights, paginate }) => {
|
||||
const pageNumbers = [];
|
||||
|
||||
for (let i = 1; i <= Math.ceil(totalHighlights / highLightsPerPage); i++) {
|
||||
pageNumbers.push(i);
|
||||
}
|
||||
|
||||
return (
|
||||
<nav>
|
||||
<ul className="pagination" style={{ marginLeft: "10px" }}>
|
||||
{pageNumbers.map((number) => (
|
||||
<li key={number} className="page-item">
|
||||
<a onClick={() => paginate(number)} href="#" className="page-link">
|
||||
{number}
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</nav>
|
||||
);
|
||||
};
|
||||
|
||||
export default Pagination;
|
|
@ -0,0 +1,85 @@
|
|||
@import '~office-ui-fabric-react/dist/sass/References.scss';
|
||||
|
||||
.reactSpFx {
|
||||
.container {
|
||||
max-width: 700px;
|
||||
margin: 0px auto;
|
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.paginationDiv{
|
||||
border: 1px solid lightblue;
|
||||
height: 100px;
|
||||
padding: 10px 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.row {
|
||||
@include ms-Grid-row;
|
||||
@include ms-fontColor-white;
|
||||
background-color: $ms-color-themeDark;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.column {
|
||||
@include ms-Grid-col;
|
||||
@include ms-lg10;
|
||||
@include ms-xl8;
|
||||
@include ms-xlPush2;
|
||||
@include ms-lgPush1;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: large;
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
@include ms-font-xl;
|
||||
@include ms-fontColor-white;
|
||||
}
|
||||
|
||||
.subTitle {
|
||||
@include ms-font-l;
|
||||
@include ms-fontColor-white;
|
||||
}
|
||||
|
||||
.description {
|
||||
@include ms-font-l;
|
||||
@include ms-fontColor-white;
|
||||
}
|
||||
|
||||
.button {
|
||||
// Our button
|
||||
text-decoration: none;
|
||||
height: 32px;
|
||||
|
||||
// Primary Button
|
||||
min-width: 80px;
|
||||
background-color: $ms-color-themePrimary;
|
||||
border-color: $ms-color-themePrimary;
|
||||
color: $ms-color-white;
|
||||
|
||||
// Basic Button
|
||||
outline: transparent;
|
||||
position: relative;
|
||||
font-family: "Segoe UI WestEuropean","Segoe UI",-apple-system,BlinkMacSystemFont,Roboto,"Helvetica Neue",sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
font-size: $ms-font-size-m;
|
||||
font-weight: $ms-font-weight-regular;
|
||||
border-width: 0;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
padding: 0 16px;
|
||||
|
||||
.label {
|
||||
font-weight: $ms-font-weight-semibold;
|
||||
font-size: $ms-font-size-m;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
margin: 0 4px;
|
||||
vertical-align: top;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
17
samples/react-soccer-highlights/src/webparts/reactSpFx/components/ReactSpFx.module.scss.d.ts
vendored
Normal file
17
samples/react-soccer-highlights/src/webparts/reactSpFx/components/ReactSpFx.module.scss.d.ts
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
// This file is automatically generated.
|
||||
// Please do not change this file!
|
||||
interface CssExports {
|
||||
'button': string;
|
||||
'column': string;
|
||||
'container': string;
|
||||
'description': string;
|
||||
'label': string;
|
||||
'ms-Grid': string;
|
||||
'paginationDiv': string;
|
||||
'reactSpFx': string;
|
||||
'row': string;
|
||||
'subTitle': string;
|
||||
'title': string;
|
||||
}
|
||||
export const cssExports: CssExports;
|
||||
export default cssExports;
|
|
@ -0,0 +1,66 @@
|
|||
import * as React from "react";
|
||||
import styles from "./ReactSpFx.module.scss";
|
||||
import { IReactSpFxProps, ISportsHighlightsState } from "./IReactSpFxProps";
|
||||
import { escape } from "@microsoft/sp-lodash-subset";
|
||||
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
|
||||
> {
|
||||
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 && (
|
||||
<Placeholder
|
||||
iconName="Soccer Highlights"
|
||||
iconText="Configure your web part"
|
||||
description="Set Web Part Title and choose Page Size to hide this section."
|
||||
buttonLabel="Configure the Web Part"
|
||||
onConfigure={this.props.onConfigure}
|
||||
/>
|
||||
)}
|
||||
{typeof this.props.title !== "undefined" && (
|
||||
<div id="mainDiv">
|
||||
<WebPartTitle
|
||||
displayMode={this.props.displayMode}
|
||||
title={this.props.title}
|
||||
updateProperty={this.props.updateProperty}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<span></span>
|
||||
<SportsHighlightsList
|
||||
sportsHighlights={this.state.sportHighlightState}
|
||||
pageSize={this.props.pageSize}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
import { videoProperties } from "office-ui-fabric-react";
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import { ISportsHighlightProps } from "./IReactSpFxProps";
|
||||
import SportsVideoList from "./SportsVideoList";
|
||||
|
||||
export default class SportsHighlight extends React.Component<
|
||||
ISportsHighlightProps
|
||||
> {
|
||||
public render() {
|
||||
const options = {
|
||||
year: "2-digit",
|
||||
month: "2-digit",
|
||||
day: "2-digit",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
};
|
||||
|
||||
const {
|
||||
title,
|
||||
id,
|
||||
date,
|
||||
side1,
|
||||
side2,
|
||||
competition,
|
||||
thumbnail,
|
||||
videos,
|
||||
} = this.props;
|
||||
return (
|
||||
<div style={{ margin: "2px" }}>
|
||||
<div style={{ display: "inline-block", marginLeft: "12px" }}>
|
||||
<div style={{ fontSize: "1.25rem", fontWeight: "bold" }}>{title}</div>
|
||||
<div style={{ fontSize: "16px", fontWeight: "bold" }}>
|
||||
{competition.name}
|
||||
</div>
|
||||
<div style={{ fontSize: "14px", fontWeight: "normal" }}>
|
||||
Date & Time: <b>{new Date(date.toString()).toLocaleString("en-US", options)}</b>
|
||||
</div>
|
||||
<div>{id}</div>
|
||||
<SportsVideoList videos={videos} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import {
|
||||
ISportsHightLightsProps,
|
||||
ISportsHighlightPagingState,
|
||||
IVideo,
|
||||
} from "./IReactSpFxProps";
|
||||
import SportsHighlight from "./SportsHighlight";
|
||||
import Paging from "react-paging";
|
||||
import Pagination from "./Pagination";
|
||||
|
||||
export default class SportsHighlightsList extends React.Component<
|
||||
ISportsHightLightsProps,
|
||||
ISportsHighlightPagingState
|
||||
> {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
currentPage: 1,
|
||||
indexOfFirstHighlight: 1,
|
||||
indexOfLastHighlight: 5,
|
||||
highLightsPerPage: this.props.pageSize,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
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,
|
||||
});
|
||||
};
|
||||
|
||||
//paginate = (pageNumber) => setCurrentPage(pageNumber);
|
||||
|
||||
render(): React.ReactElement<ISportsHightLightsProps> {
|
||||
const sportsHighlights = this.props.sportsHighlights;
|
||||
var {
|
||||
currentPage,
|
||||
indexOfFirstHighlight,
|
||||
indexOfLastHighlight,
|
||||
} = this.state;
|
||||
|
||||
|
||||
if (typeof indexOfFirstHighlight === "undefined" || indexOfFirstHighlight == 0)
|
||||
{
|
||||
indexOfFirstHighlight=1
|
||||
}
|
||||
|
||||
if (
|
||||
typeof indexOfFirstHighlight === "undefined" ||
|
||||
indexOfFirstHighlight == 0
|
||||
) {
|
||||
indexOfFirstHighlight = 1;
|
||||
}
|
||||
const CurrentsportsHighlights = this.props.sportsHighlights.slice(
|
||||
indexOfFirstHighlight,
|
||||
indexOfLastHighlight
|
||||
);
|
||||
|
||||
console.clear();
|
||||
console.log("indexOfFirstHighlight:" + indexOfFirstHighlight);
|
||||
console.log("indexOfLastHighlight : " + indexOfLastHighlight);
|
||||
console.log("currentPage :" + currentPage);
|
||||
console.log("Page Size :" + this.props.pageSize);
|
||||
|
||||
//this.updateLastPage(currentPage);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="paginationDiv">
|
||||
<Pagination
|
||||
highLightsPerPage={10}
|
||||
totalHighlights={sportsHighlights.length}
|
||||
paginate={this.paginate}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
{CurrentsportsHighlights.map((highLight, i) => (
|
||||
<SportsHighlight {...highLight} key={i} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import { IVideo } from "./IReactSpFxProps";
|
||||
import ReactMarkdownWithHtml from "react-markdown/with-html";
|
||||
import { body } from "@pnp/pnpjs";
|
||||
|
||||
export default class SportsVideo extends React.Component<IVideo> {
|
||||
public render() {
|
||||
const { title, embed } = this.props;
|
||||
return (
|
||||
<div>
|
||||
<div
|
||||
style={{ fontSize: "12px", 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" }}
|
||||
title={"click to play " + title}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import { IVidesList } from "./IReactSpFxProps";
|
||||
import SportsVideo from "./SportsVideo";
|
||||
import ReactMarkdownWithHtml from "react-markdown/with-html";
|
||||
|
||||
export default class SportsVideoList extends React.Component<IVidesList> {
|
||||
public render() {
|
||||
const videos = this.props.videos;
|
||||
return (
|
||||
<div style={{ margin: "1px" }}>
|
||||
{this.props.videos.map((video, i) => (
|
||||
<SportsVideo
|
||||
key={i}
|
||||
embed={video.embed}
|
||||
title={video.title}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
define([], function() {
|
||||
return {
|
||||
"PropertyPaneDescription": "Title",
|
||||
"BasicGroupName": "General",
|
||||
"DescriptionFieldLabel": "Title"
|
||||
}
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
declare interface IReactSpFxWebPartStrings {
|
||||
PropertyPaneDescription: string;
|
||||
BasicGroupName: string;
|
||||
DescriptionFieldLabel: string;
|
||||
}
|
||||
|
||||
declare module 'ReactSpFxWebPartStrings' {
|
||||
const strings: IReactSpFxWebPartStrings;
|
||||
export = strings;
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
Binary file not shown.
After Width: | Height: | Size: 383 B |
Loading…
Reference in New Issue