Merge pull request #2101 from Adam-it/react-find-parker-webpart
new react webpart for Halloween 🎃🎃🎃 (react-find-parker)
|
@ -0,0 +1,33 @@
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
|
||||||
|
# Dependency directories
|
||||||
|
node_modules
|
||||||
|
|
||||||
|
# Build generated files
|
||||||
|
dist
|
||||||
|
lib
|
||||||
|
release
|
||||||
|
solution
|
||||||
|
temp
|
||||||
|
*.sppkg
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
|
||||||
|
# OSX
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Visual Studio files
|
||||||
|
.ntvs_analysis.dat
|
||||||
|
.vs
|
||||||
|
bin
|
||||||
|
obj
|
||||||
|
|
||||||
|
# Resx Generated Code
|
||||||
|
*.resx.ts
|
||||||
|
|
||||||
|
# Styles Generated Code
|
||||||
|
*.scss.ts
|
|
@ -0,0 +1,16 @@
|
||||||
|
!dist
|
||||||
|
config
|
||||||
|
|
||||||
|
gulpfile.js
|
||||||
|
|
||||||
|
release
|
||||||
|
src
|
||||||
|
temp
|
||||||
|
|
||||||
|
tsconfig.json
|
||||||
|
tslint.json
|
||||||
|
|
||||||
|
*.log
|
||||||
|
|
||||||
|
.yo-rc.json
|
||||||
|
.vscode
|
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"@microsoft/generator-sharepoint": {
|
||||||
|
"plusBeta": false,
|
||||||
|
"isCreatingSolution": true,
|
||||||
|
"environment": "spo",
|
||||||
|
"version": "1.13.0",
|
||||||
|
"libraryName": "react-find-parker",
|
||||||
|
"libraryId": "5659e702-453b-4b73-9ead-fa1859234a18",
|
||||||
|
"packageManager": "npm",
|
||||||
|
"isDomainIsolated": false,
|
||||||
|
"componentType": "webpart"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
# Find Parker
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
Work is not about work 🤨, sometimes a bit of fun is in order 🕹️.
|
||||||
|
This webpart is a simple find object game.
|
||||||
|
![parker](./assets/parker.gif)
|
||||||
|
|
||||||
|
User may set up how many elements will she or he be looking for in the property pane
|
||||||
|
![config](./assets/config.png)
|
||||||
|
|
||||||
|
By changing the icon svg image we may create a find easter egg 🥚 game or find pumpkins for Halloween 🎃🎃🎃
|
||||||
|
![halloween](./assets/halloween.gif)
|
||||||
|
![findpumpkin](./assets/findpumpkin.png)
|
||||||
|
|
||||||
|
or good old where's Wally game 😉
|
||||||
|
![findWally](./assets/findWally.png)
|
||||||
|
|
||||||
|
|
||||||
|
## Compatibility
|
||||||
|
|
||||||
|
![SPFx 1.13.0](https://img.shields.io/badge/SPFx-1.13.0-green.svg)
|
||||||
|
![Node.js v14 | v12 | v10](https://img.shields.io/badge/Node.js-v14%20%7C%20v12%20%7C%20v10-green.svg)
|
||||||
|
![Compatible with SharePoint Online](https://img.shields.io/badge/SharePoint%20Online-Compatible-green.svg)
|
||||||
|
![Does not work with SharePoint 2019](https://img.shields.io/badge/SharePoint%20Server%202019-Incompatible-red.svg "SharePoint Server 2019 requires SPFx 1.4.1 or lower")
|
||||||
|
![Does not work with SharePoint 2016 (Feature Pack 2)](https://img.shields.io/badge/SharePoint%20Server%202016%20(Feature%20Pack%202)-Incompatible-red.svg "SharePoint Server 2016 Feature Pack 2 requires SPFx 1.1")
|
||||||
|
![Local Workbench Unsupported](https://img.shields.io/badge/Local%20Workbench-Unsupported-red.svg "Local workbench is no longer available as of SPFx 1.13 and above")
|
||||||
|
![Hosted Workbench Partially](https://img.shields.io/badge/Hosted%20Workbench-Partially-yellow.svg "Will run on hosted workbench, but web part works better on a hosted page with content")
|
||||||
|
|
||||||
|
## Applies to
|
||||||
|
|
||||||
|
- [SharePoint Framework](https://aka.ms/spfx)
|
||||||
|
- [Microsoft 365 tenant](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/set-up-your-developer-tenant)
|
||||||
|
|
||||||
|
|
||||||
|
## Solution
|
||||||
|
|
||||||
|
Solution|Author(s)
|
||||||
|
--------|---------
|
||||||
|
react-find-parker | [Adam Wojcik](https://github.com/Adam-it)
|
||||||
|
|
||||||
|
## Version history
|
||||||
|
|
||||||
|
Version|Date|Comments
|
||||||
|
-------|----|--------
|
||||||
|
1.0|october 31, 2021|Halloween 🎃🎃🎃 & Initial release
|
||||||
|
|
||||||
|
## Minimal Path to Awesome
|
||||||
|
|
||||||
|
- Clone this repository
|
||||||
|
- Ensure that you are at the solution folder
|
||||||
|
- in the command-line run:
|
||||||
|
- `npm install`
|
||||||
|
- `gulp serve`
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
This project contains sample client-side web parts built on the SharePoint Framework using React
|
||||||
|
- using React for building SharePoint Framework client-side web parts
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- [Getting started with SharePoint Framework](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/set-up-your-developer-tenant)
|
||||||
|
- [Publish SharePoint Framework applications to the Marketplace](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/publish-to-marketplace-overview)
|
||||||
|
- [Microsoft 365 Patterns and Practices](https://aka.ms/m365pnp) - Guidance, tooling, samples and open-source controls for your Microsoft 365 development
|
||||||
|
|
||||||
|
## Disclaimer
|
||||||
|
|
||||||
|
**THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.**
|
||||||
|
|
||||||
|
## Help
|
||||||
|
|
||||||
|
We do not support samples, but we this community is always willing to help, and we want to improve these samples. We use GitHub to track issues, which makes it easy for community members to volunteer their time and help resolve issues.
|
||||||
|
|
||||||
|
If you're having issues building the solution, please run [spfx doctor](https://pnp.github.io/cli-microsoft365/cmd/spfx/spfx-doctor/) from within the solution folder to diagnose incompatibility issues with your environment.
|
||||||
|
|
||||||
|
You can try looking at [issues related to this sample](https://github.com/pnp/sp-dev-fx-webparts/issues?q=label%3Areact-find-parker) to see if anybody else is having the same issues.
|
||||||
|
|
||||||
|
You can also try looking at [discussions related to this sample](https://github.com/pnp/sp-dev-fx-webparts/discussions?discussions_q=label%3Areact-find-parker) and see what the community is saying.
|
||||||
|
|
||||||
|
If you encounter any issues while using this sample, [create a new issue](https://github.com/pnp/sp-dev-fx-webparts/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2Ctype%3Abug-suspected&template=bug-report.yml&sample=react-find-parker&authors=@Adam-it&title=react-find-parker%20-%20).
|
||||||
|
|
||||||
|
For questions regarding this sample, [create a new question](https://github.com/pnp/sp-dev-fx-webparts/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2Ctype%3Abug-suspected&template=question.yml&sample=react-find-parker&authors=@Adam-it&title=react-find-parker%20-%20).
|
||||||
|
|
||||||
|
Finally, if you have an idea for improvement, [make a suggestion](https://github.com/pnp/sp-dev-fx-webparts/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2Ctype%3Abug-suspected&template=suggestion.yml&sample=react-find-parker&authors=@Adam-it&title=react-find-parker%20-%20).
|
||||||
|
|
||||||
|
<img src="https://telemetry.sharepointpnp.com/sp-dev-fx-webparts/samples/react-find-parker" />
|
After Width: | Height: | Size: 194 KiB |
After Width: | Height: | Size: 504 KiB |
After Width: | Height: | Size: 100 KiB |
After Width: | Height: | Size: 92 KiB |
After Width: | Height: | Size: 2.1 MiB |
After Width: | Height: | Size: 2.0 MiB |
|
@ -0,0 +1,51 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "pnp-sp-dev-spfx-web-parts-react-find-parker",
|
||||||
|
"source": "pnp",
|
||||||
|
"title": "Find Parker",
|
||||||
|
"shortDescription": "This webpart is a simple find object game.",
|
||||||
|
"url": "https://github.com/pnp/sp-dev-fx-webparts/tree/main/samples/react-find-parker",
|
||||||
|
"longDescription": [
|
||||||
|
"Work is not about work 🤨, sometimes a bit of fun is in order 🕹️",
|
||||||
|
"This webpart is a simple find object game."
|
||||||
|
],
|
||||||
|
"creationDateTime": "2021-10-31",
|
||||||
|
"updateDateTime": "2021-10-31",
|
||||||
|
"products": [
|
||||||
|
"SharePoint",
|
||||||
|
"Office"
|
||||||
|
],
|
||||||
|
"metadata": [
|
||||||
|
{
|
||||||
|
"key": "CLIENT-SIDE-DEV",
|
||||||
|
"value": "React"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "SPFX-VERSION",
|
||||||
|
"value": "1.13.0"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"thumbnails": [
|
||||||
|
{
|
||||||
|
"type": "image",
|
||||||
|
"order": 100,
|
||||||
|
"url": "https://github.com/pnp/sp-dev-fx-webparts/raw/main/samples/react-find-parker/assets/parker.gif",
|
||||||
|
"alt": "Find Parker"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"gitHubAccount": "Adam-it",
|
||||||
|
"pictureUrl": "https://github.com/Adam-it.png",
|
||||||
|
"name": "Adam Wojcik"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"name": "Build your first SharePoint client-side web part",
|
||||||
|
"description": "Client-side web parts are client-side components that run in the context of a SharePoint page. Client-side web parts can be deployed to SharePoint environments that support the SharePoint Framework. You can also use modern JavaScript web frameworks, tools, and libraries to build them.",
|
||||||
|
"url": "https://docs.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/get-started/build-a-hello-world-web-part"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/config.2.0.schema.json",
|
||||||
|
"version": "2.0",
|
||||||
|
"bundles": {
|
||||||
|
"find-parker-web-part": {
|
||||||
|
"components": [
|
||||||
|
{
|
||||||
|
"entrypoint": "./lib/webparts/findParker/FindParkerWebPart.js",
|
||||||
|
"manifest": "./src/webparts/findParker/FindParkerWebPart.manifest.json"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"externals": {},
|
||||||
|
"localizedResources": {
|
||||||
|
"FindParkerWebPartStrings": "lib/webparts/findParker/loc/{locale}.js"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/deploy-azure-storage.schema.json",
|
||||||
|
"workingDir": "./release/assets/",
|
||||||
|
"account": "<!-- STORAGE ACCOUNT NAME -->",
|
||||||
|
"container": "react-find-parker",
|
||||||
|
"accessKey": "<!-- ACCESS KEY -->"
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json",
|
||||||
|
"solution": {
|
||||||
|
"name": "react-find-parker-client-side-solution",
|
||||||
|
"id": "5659e702-453b-4b73-9ead-fa1859234a18",
|
||||||
|
"version": "1.0.0.0",
|
||||||
|
"includeClientSideAssets": true,
|
||||||
|
"skipFeatureDeployment": true,
|
||||||
|
"isDomainIsolated": false,
|
||||||
|
"developer": {
|
||||||
|
"name": "",
|
||||||
|
"websiteUrl": "",
|
||||||
|
"privacyUrl": "",
|
||||||
|
"termsOfUseUrl": "",
|
||||||
|
"mpnId": "Undefined-1.13.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"paths": {
|
||||||
|
"zippedPackage": "solution/react-find-parker.sppkg"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://developer.microsoft.com/json-schemas/core-build/serve.schema.json",
|
||||||
|
"port": 4321,
|
||||||
|
"https": true,
|
||||||
|
"initialPage": "https://tenanttocheck.sharepoint.com/_layouts/workbench.aspx"
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/write-manifests.schema.json",
|
||||||
|
"cdnBasePath": "<!-- PATH TO CDN -->"
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const build = require('@microsoft/sp-build-web');
|
||||||
|
|
||||||
|
build.addSuppression(`Warning - [sass] The local CSS class 'ms-Grid' is not camelCase and will not be type-safe.`);
|
||||||
|
|
||||||
|
var getTasks = build.rig.getTasks;
|
||||||
|
build.rig.getTasks = function () {
|
||||||
|
var result = getTasks.call(build.rig);
|
||||||
|
|
||||||
|
result.set('serve', result.get('serve-deprecated'));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
build.initialize(require('gulp'));
|
|
@ -0,0 +1,32 @@
|
||||||
|
{
|
||||||
|
"name": "react-find-parker",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"private": true,
|
||||||
|
"main": "lib/index.js",
|
||||||
|
"scripts": {
|
||||||
|
"build": "gulp bundle",
|
||||||
|
"clean": "gulp clean",
|
||||||
|
"test": "gulp test"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"react": "16.13.1",
|
||||||
|
"react-dom": "16.13.1",
|
||||||
|
"office-ui-fabric-react": "7.174.1",
|
||||||
|
"@microsoft/sp-core-library": "1.13.0",
|
||||||
|
"@microsoft/sp-property-pane": "1.13.0",
|
||||||
|
"@microsoft/sp-webpart-base": "1.13.0",
|
||||||
|
"@microsoft/sp-lodash-subset": "1.13.0",
|
||||||
|
"@microsoft/sp-office-ui-fabric-core": "1.13.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/react": "16.9.51",
|
||||||
|
"@types/react-dom": "16.9.8",
|
||||||
|
"@microsoft/sp-build-web": "1.13.0",
|
||||||
|
"@microsoft/sp-tslint-rules": "1.13.0",
|
||||||
|
"@microsoft/sp-module-interfaces": "1.13.0",
|
||||||
|
"@microsoft/rush-stack-compiler-3.9": "0.4.47",
|
||||||
|
"gulp": "~4.0.2",
|
||||||
|
"ajv": "~5.2.2",
|
||||||
|
"@types/webpack-env": "1.13.1"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
// A file is required to be in the root of the /src directory by the TypeScript compiler
|
|
@ -0,0 +1,28 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://developer.microsoft.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
|
||||||
|
"id": "5a233f7d-d5aa-4af4-97b3-ada5befdf3cf",
|
||||||
|
"alias": "FindParkerWebPart",
|
||||||
|
"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", "TeamsPersonalApp", "TeamsTab", "SharePointFullPage"],
|
||||||
|
"supportsThemeVariants": true,
|
||||||
|
|
||||||
|
"preconfiguredEntries": [{
|
||||||
|
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other
|
||||||
|
"group": { "default": "Other" },
|
||||||
|
"title": { "default": "FindParker" },
|
||||||
|
"description": { "default": "FindParker description" },
|
||||||
|
"officeFabricIconFontName": "Page",
|
||||||
|
"properties": {
|
||||||
|
"numberOfElements": 3
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
import * as React from 'react';
|
||||||
|
import * as ReactDom from 'react-dom';
|
||||||
|
import * as strings from 'FindParkerWebPartStrings';
|
||||||
|
import { Version } from '@microsoft/sp-core-library';
|
||||||
|
import { IPropertyPaneConfiguration, PropertyPaneSlider } from '@microsoft/sp-property-pane';
|
||||||
|
import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base';
|
||||||
|
import FindParker from './components/FindParker/FindParker';
|
||||||
|
import { IFindParkerProps } from './components//FindParker/IFindParkerProps';
|
||||||
|
import { IFindParkerWebPartProps } from './IFindParkerWebPartProps';
|
||||||
|
|
||||||
|
export default class FindParkerWebPart extends BaseClientSideWebPart<IFindParkerWebPartProps> {
|
||||||
|
|
||||||
|
public render(): void {
|
||||||
|
const element: React.ReactElement<IFindParkerProps> = React.createElement(
|
||||||
|
FindParker,
|
||||||
|
{
|
||||||
|
numberOfElements: this.properties.numberOfElements
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
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.PropertyPaneBasicGroupName,
|
||||||
|
groupFields: [
|
||||||
|
PropertyPaneSlider('numberOfElements', {
|
||||||
|
label: strings.PropertyPaneNumberOfElementsFieldLabel,
|
||||||
|
min: 1,
|
||||||
|
max: 20,
|
||||||
|
value: 5,
|
||||||
|
showValue: true,
|
||||||
|
step: 1
|
||||||
|
})
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
export interface IFindParkerWebPartProps {
|
||||||
|
numberOfElements: number;
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
@import "~office-ui-fabric-react/dist/sass/References.scss";
|
||||||
|
@import "../../../styles/Common.module.scss";
|
||||||
|
|
||||||
|
.findParker {
|
||||||
|
.container {
|
||||||
|
background-color: $neutralLight;
|
||||||
|
padding-top: 10px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
|
||||||
|
.row {
|
||||||
|
@include ms-Grid-row;
|
||||||
|
|
||||||
|
.column {
|
||||||
|
@include ms-Grid-col;
|
||||||
|
@include ms-lg10;
|
||||||
|
@include ms-xl8;
|
||||||
|
@include ms-xlPush2;
|
||||||
|
@include ms-lgPush1;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
@include ms-font-xxl;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
@include ms-font-m;
|
||||||
|
text-align: justify;
|
||||||
|
margin-top: 0px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.parkersContener {
|
||||||
|
.parker {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,163 @@
|
||||||
|
import * as React from 'react';
|
||||||
|
import * as strings from 'FindParkerWebPartStrings';
|
||||||
|
import styles from './FindParker.module.scss';
|
||||||
|
import { IFindParkerProps } from './IFindParkerProps';
|
||||||
|
import { IFindParkerState } from './IFindParkerState';
|
||||||
|
import { DefaultButton } from '@microsoft/office-ui-fabric-react-bundle/node_modules/office-ui-fabric-react/lib/Button';
|
||||||
|
import Constants from '../../model/Constants';
|
||||||
|
import Icon from '../../model/Icon';
|
||||||
|
import IParker from '../../model/IParker';
|
||||||
|
|
||||||
|
export default class FindParker extends React.Component<IFindParkerProps, IFindParkerState> {
|
||||||
|
|
||||||
|
constructor(props: IFindParkerProps) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
numberOfFoundElements: 0,
|
||||||
|
gameStarted: false,
|
||||||
|
gameFinsihed: false,
|
||||||
|
foundPlaceForParkers: false,
|
||||||
|
listOfParkers: [],
|
||||||
|
elements: []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public componentDidMount(): void {
|
||||||
|
const { numberOfElements } = this.props;
|
||||||
|
|
||||||
|
if(document.querySelector(Constants.mainPageContent) === null){
|
||||||
|
this.setState({ foundPlaceForParkers: false });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const listOfParkers = this.createListOfParkers(numberOfElements);
|
||||||
|
this.setState(
|
||||||
|
{
|
||||||
|
listOfParkers: listOfParkers,
|
||||||
|
foundPlaceForParkers: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public render(): React.ReactElement<IFindParkerProps> {
|
||||||
|
|
||||||
|
const {
|
||||||
|
gameStarted,
|
||||||
|
gameFinsihed,
|
||||||
|
foundPlaceForParkers,
|
||||||
|
numberOfFoundElements,
|
||||||
|
elements } = this.state;
|
||||||
|
const { numberOfElements } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div id='findParkerId' className={styles.findParker}>
|
||||||
|
<div className={styles.container}>
|
||||||
|
<div className={styles.row}>
|
||||||
|
<div className={styles.column}>
|
||||||
|
<p className={styles.title}>{strings.GameTitle}</p>
|
||||||
|
{foundPlaceForParkers ?
|
||||||
|
<p className={styles.label}>{strings.GameDescription}</p>
|
||||||
|
:
|
||||||
|
<p className={styles.label}>{strings.CouldNotFindPlaceForParkersDescription}</p>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{!gameStarted ?
|
||||||
|
<div className={styles.row}>
|
||||||
|
<div className={styles.column}>
|
||||||
|
{foundPlaceForParkers ?
|
||||||
|
<DefaultButton onClick={() => this.startGame()}>{strings.StartGameButton}</DefaultButton>
|
||||||
|
: ''
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
:
|
||||||
|
<div className={styles.row}>
|
||||||
|
{!gameFinsihed ?
|
||||||
|
<div className={styles.column}>
|
||||||
|
<p className={styles.label}>{strings.GameProgressELementsLabel} <strong>{numberOfElements}</strong></p>
|
||||||
|
<p className={styles.label}>{strings.GameProgressLabel} <strong>{numberOfFoundElements}</strong></p>
|
||||||
|
</div>
|
||||||
|
:
|
||||||
|
<div className={styles.column}>
|
||||||
|
<p className={styles.label}>{strings.EndGameMessage}</p>
|
||||||
|
<DefaultButton onClick={() => this.restartGame()}>{strings.RestartGameButton}</DefaultButton>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<div className={styles.parkersContener}>
|
||||||
|
{elements}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderParkers(listOfParkers: Array<IParker>): void {
|
||||||
|
let items = [];
|
||||||
|
listOfParkers.forEach(parker => {
|
||||||
|
const style = {
|
||||||
|
top: parker.top,
|
||||||
|
left: parker.left,
|
||||||
|
transform: parker.transform
|
||||||
|
};
|
||||||
|
items.push(<img alt='pnpParker' src={Icon.svg} width='65' className={styles.parker} style={style} onClick={() => this.parkerFound(parker.id)} />);
|
||||||
|
});
|
||||||
|
this.setState({ elements: items });
|
||||||
|
}
|
||||||
|
|
||||||
|
private parkerFound(id: number): void {
|
||||||
|
let numberOfFoundElements = this.state.numberOfFoundElements + 1;
|
||||||
|
this.setState({ numberOfFoundElements: numberOfFoundElements });
|
||||||
|
let parkers = this.state.listOfParkers;
|
||||||
|
parkers = parkers.filter(parker => parker.id !== id);
|
||||||
|
this.setState({ listOfParkers: parkers });
|
||||||
|
this.renderParkers(parkers);
|
||||||
|
|
||||||
|
if (numberOfFoundElements === this.props.numberOfElements) {
|
||||||
|
this.setState({ gameFinsihed: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private startGame(): void {
|
||||||
|
this.setState({ gameStarted: true });
|
||||||
|
this.renderParkers(this.state.listOfParkers);
|
||||||
|
}
|
||||||
|
|
||||||
|
private restartGame(): void {
|
||||||
|
const { numberOfElements } = this.props;
|
||||||
|
this.setState({ gameFinsihed: false });
|
||||||
|
const listOfParkers = this.createListOfParkers(numberOfElements);
|
||||||
|
this.setState({
|
||||||
|
listOfParkers: listOfParkers,
|
||||||
|
numberOfFoundElements: 0
|
||||||
|
});
|
||||||
|
this.renderParkers(listOfParkers);
|
||||||
|
}
|
||||||
|
|
||||||
|
private createListOfParkers(numberOfElements: number): Array<IParker> {
|
||||||
|
const pageHeight: number = document.querySelector(Constants.mainPageContent).scrollHeight;
|
||||||
|
const pageWidth: number = document.querySelector(Constants.mainPageContent).scrollWidth;
|
||||||
|
const findParkerWebPart = document.getElementById('findParkerId').getBoundingClientRect();
|
||||||
|
let listOfParkers = [];
|
||||||
|
for (let index = 0; index < numberOfElements; index++) {
|
||||||
|
const y: number = this.randomNumber((0 - findParkerWebPart.y + 185), (pageHeight - findParkerWebPart.y - 300));
|
||||||
|
const x: number = this.randomNumber((0 - findParkerWebPart.x + 100), (pageWidth - findParkerWebPart.x - 300));
|
||||||
|
const rotate: number = this.randomNumber(0, 180);
|
||||||
|
const parker: IParker = {
|
||||||
|
id: index,
|
||||||
|
left: x,
|
||||||
|
top: y,
|
||||||
|
transform: `rotate(${rotate}deg)`
|
||||||
|
};
|
||||||
|
listOfParkers.push(parker);
|
||||||
|
}
|
||||||
|
|
||||||
|
return listOfParkers;
|
||||||
|
}
|
||||||
|
|
||||||
|
private randomNumber(min: number, max: number): number {
|
||||||
|
return Math.floor(Math.random() * (max - min + 1) + min);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
export interface IFindParkerProps {
|
||||||
|
numberOfElements: number;
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
import IParker from "../../model/IParker";
|
||||||
|
|
||||||
|
export interface IFindParkerState {
|
||||||
|
numberOfFoundElements: number;
|
||||||
|
listOfParkers: Array<IParker>;
|
||||||
|
elements: Array<React.ReactElement>;
|
||||||
|
gameStarted: boolean;
|
||||||
|
gameFinsihed: boolean;
|
||||||
|
foundPlaceForParkers: boolean;
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
define([], function() {
|
||||||
|
return {
|
||||||
|
"PropertyPaneDescription": "Settings",
|
||||||
|
"PropertyPaneBasicGroupName": "Elements settings",
|
||||||
|
"PropertyPaneNumberOfElementsFieldLabel": "number of elements to find",
|
||||||
|
"GameTitle": "Find Parker",
|
||||||
|
"GameDescription": "🎯 The goal of the game is to find all elements on the page.",
|
||||||
|
"CouldNotFindPlaceForParkersDescription": "🙄 Your page seems strange, I don't see any playground to play here 😉",
|
||||||
|
"StartGameButton": "🎮 Start the game !",
|
||||||
|
"RestartGameButton": "🎮 It was fun, lets try again",
|
||||||
|
"EndGameMessage": "Congrats! You are awesome 👍👍👍",
|
||||||
|
"GameProgressELementsLabel": "🔍 Elements to find: ",
|
||||||
|
"GameProgressLabel": "👉 You found: "
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,18 @@
|
||||||
|
declare interface IFindParkerWebPartStrings {
|
||||||
|
PropertyPaneDescription: string;
|
||||||
|
PropertyPaneBasicGroupName: string;
|
||||||
|
PropertyPaneNumberOfElementsFieldLabel: string;
|
||||||
|
GameTitle: string;
|
||||||
|
GameDescription: string;
|
||||||
|
CouldNotFindPlaceForParkersDescription: string;
|
||||||
|
StartGameButton: string;
|
||||||
|
RestartGameButton: string;
|
||||||
|
EndGameMessage: string;
|
||||||
|
GameProgressELementsLabel: string;
|
||||||
|
GameProgressLabel: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'FindParkerWebPartStrings' {
|
||||||
|
const strings: IFindParkerWebPartStrings;
|
||||||
|
export = strings;
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
export default class Constants {
|
||||||
|
public static mainPageContent: string = 'div[data-automation-id=\'contentScrollRegion\'][role=\'main\']';
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
export default class IParker {
|
||||||
|
public id: number;
|
||||||
|
public top: number;
|
||||||
|
public left: number;
|
||||||
|
public transform: string;
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
@import "~office-ui-fabric-react/dist/sass/References.scss";
|
||||||
|
|
||||||
|
// colors
|
||||||
|
$themePrimary: "[theme: themePrimary, default: #0078d7]";
|
||||||
|
$themeLighterAlt: "[theme: themeLighterAlt, default: #eff6fc]";
|
||||||
|
$themeLighter: "[theme: themeLighter, default: #deecf9]";
|
||||||
|
$themeLight: "[theme: themeLight, default: #c7e0f4]";
|
||||||
|
$themeTertiary: "[theme: themeTertiary, default: #71afe5]";
|
||||||
|
$themeSecondary: "[theme: themeSecondary, default: #2b88d8]";
|
||||||
|
$themeDarkAlt: "[theme: themeDarkAlt, default: #106ebe]";
|
||||||
|
$themeDark: "[theme: themeDark, default: #005a9e]";
|
||||||
|
$themeDarker: "[theme: themeDarker, default: #004578]";
|
||||||
|
$neutralLighterAlt: "[theme: neutralLighterAlt, default: #f8f8f8]";
|
||||||
|
$neutralLighter: "[theme: neutralLighter, default: #f4f4f4]";
|
||||||
|
$neutralLight: "[theme: neutralLight, default: #eaeaea]";
|
||||||
|
$neutralQuaternaryAlt: "[theme: neutralQuaternaryAlt, default: #dadada]";
|
||||||
|
$neutralQuaternary: "[theme: neutralQuaternary, default: #d0d0d0]";
|
||||||
|
$neutralTertiaryAlt: "[theme: neutralTertiaryAlt, default: #c8c8c8]";
|
||||||
|
$neutralTertiary: "[theme: neutralTertiary, default: #a6a6a6]";
|
||||||
|
$neutralSecondaryAlt: "[theme: neutralSecondaryAlt, default: #767676]";
|
||||||
|
$neutralSecondary: "[theme: neutralSecondary, default: #666666]";
|
||||||
|
$neutralPrimaryAlt: "[theme: neutralPrimaryAlt, default: #3c3c3c]";
|
||||||
|
$neutralPrimary: "[theme: neutralPrimary, default: #333]";
|
||||||
|
$neutralDark: "[theme: neutralDark, default: #212121]";
|
||||||
|
$black: "[theme: black, default: #000000]";
|
||||||
|
$white: "[theme: white, default: #fff]";
|
||||||
|
$primaryBackground: "[theme: primaryBackground, default: #fff]";
|
||||||
|
$primaryText: "[theme: primaryText, default: #333]";
|
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 542 B |
|
@ -0,0 +1,35 @@
|
||||||
|
{
|
||||||
|
"extends": "./node_modules/@microsoft/rush-stack-compiler-3.9/includes/tsconfig-web.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es5",
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"jsx": "react",
|
||||||
|
"declaration": true,
|
||||||
|
"sourceMap": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"outDir": "lib",
|
||||||
|
"inlineSources": false,
|
||||||
|
"strictNullChecks": false,
|
||||||
|
"noUnusedLocals": false,
|
||||||
|
"typeRoots": [
|
||||||
|
"./node_modules/@types",
|
||||||
|
"./node_modules/@microsoft"
|
||||||
|
],
|
||||||
|
"types": [
|
||||||
|
"webpack-env"
|
||||||
|
],
|
||||||
|
"lib": [
|
||||||
|
"es5",
|
||||||
|
"dom",
|
||||||
|
"es2015.collection",
|
||||||
|
"es2015.promise"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src/**/*.ts",
|
||||||
|
"src/**/*.tsx"
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
"extends": "./node_modules/@microsoft/sp-tslint-rules/base-tslint.json",
|
||||||
|
"rules": {
|
||||||
|
"class-name": false,
|
||||||
|
"export-name": false,
|
||||||
|
"forin": false,
|
||||||
|
"label-position": false,
|
||||||
|
"member-access": true,
|
||||||
|
"no-arg": false,
|
||||||
|
"no-console": false,
|
||||||
|
"no-construct": false,
|
||||||
|
"no-duplicate-variable": true,
|
||||||
|
"no-eval": false,
|
||||||
|
"no-function-expression": true,
|
||||||
|
"no-internal-module": true,
|
||||||
|
"no-shadowed-variable": true,
|
||||||
|
"no-switch-case-fall-through": true,
|
||||||
|
"no-unnecessary-semicolons": true,
|
||||||
|
"no-unused-expression": true,
|
||||||
|
"no-with-statement": true,
|
||||||
|
"semicolon": true,
|
||||||
|
"trailing-comma": false,
|
||||||
|
"typedef": false,
|
||||||
|
"typedef-whitespace": false,
|
||||||
|
"use-named-parameter": true,
|
||||||
|
"variable-name": false,
|
||||||
|
"whitespace": false
|
||||||
|
}
|
||||||
|
}
|