Merge pull request #1978 from omarelanis/master
This commit is contained in:
commit
c2addb4c66
|
@ -33,6 +33,7 @@ hero-webpart | [Omar El-Anis](https://github.com/omarelanis) @ SP Bytes www.spby
|
|||
|
||||
Version|Date|Comments
|
||||
-------|----|--------
|
||||
1.2|July 27, 2021|Updated to automatically detect how many items are being displayed and adjust the display layout based on this<br/>Updated design to show the title on all images<br/>Updated description area on hover<br/>Updated hover effect of image to show a zoom effect when hovering over an item<br/>General cleaning up of CSS and code
|
||||
1.1|March 10, 2021|Update comment
|
||||
1.0|January 29, 2021|Initial release
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
"This solution creates a customisable Hero web part, it uses a stored collection from the PnP PropertyFieldCollectionData control "
|
||||
],
|
||||
"creationDateTime": "2021-04-02",
|
||||
"updateDateTime": "2021-04-02",
|
||||
"updateDateTime": "2021-07-27",
|
||||
"products": [
|
||||
"SharePoint",
|
||||
"Office"
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"solution": {
|
||||
"name": "Hero Layout Webpart",
|
||||
"id": "5efc0426-3e59-4fc7-b638-73eb77aaf788",
|
||||
"version": "1.0.0.0",
|
||||
"version": "1.2.0.0",
|
||||
"includeClientSideAssets": true,
|
||||
"skipFeatureDeployment": true,
|
||||
"isDomainIsolated": false,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "hero-webpart",
|
||||
"version": "0.0.1",
|
||||
"version": "1.2.0",
|
||||
"private": true,
|
||||
"main": "lib/index.js",
|
||||
"scripts": {
|
||||
|
|
|
@ -26,7 +26,8 @@
|
|||
"isPaginated": false,
|
||||
"hideFirstPageJump": false,
|
||||
"hideLastPageJump": false,
|
||||
"showAllHero": false
|
||||
"showAllHero": false,
|
||||
"totalShow": 5
|
||||
}
|
||||
}
|
||||
],
|
||||
|
|
|
@ -25,7 +25,8 @@
|
|||
"isPaginated":false,
|
||||
"hideFirstPageJump":false,
|
||||
"hideLastPageJump":false,
|
||||
"showAllHero":false
|
||||
"showAllHero":false,
|
||||
"totalShow":5
|
||||
}
|
||||
}]
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import HeroWebpart from './components/HeroWebpart';
|
|||
import { IHeroWebpartProps } from './components/IHeroWebpartProps';
|
||||
|
||||
import { PropertyFieldToggleWithCallout } from '@pnp/spfx-property-controls/lib/PropertyFieldToggleWithCallout';
|
||||
import { PropertyFieldSliderWithCallout } from '@pnp/spfx-property-controls/lib/PropertyFieldSliderWithCallout';
|
||||
import { CalloutTriggers } from '@pnp/spfx-property-controls/lib/PropertyFieldHeader';
|
||||
|
||||
import { PropertyFieldCollectionData, CustomCollectionFieldType } from '@pnp/spfx-property-controls/lib/PropertyFieldCollectionData';
|
||||
|
@ -105,27 +106,28 @@ export default class HeroWebpartWebPart extends BaseClientSideWebPart<IHeroWebpa
|
|||
title: "Select File",
|
||||
type: CustomCollectionFieldType.custom,
|
||||
onCustomRender: (field, value, onUpdate, item, itemId, onError) => {
|
||||
return (
|
||||
React.createElement(FilePicker, {
|
||||
key: itemId,
|
||||
context: this.context,
|
||||
buttonLabel:"Select File",
|
||||
onChange: (selectedFile: IFilePickerResult[]) => {
|
||||
onUpdate(field.id, selectedFile);
|
||||
return (
|
||||
React.createElement(FilePicker, {
|
||||
key: itemId,
|
||||
context: this.context,
|
||||
buttonLabel:"Select File",
|
||||
onChange: (selectedFile: IFilePickerResult[]) => {
|
||||
onUpdate(field.id, selectedFile);
|
||||
return Event;
|
||||
},
|
||||
onSave: (filePickerResult: IFilePickerResult[]) => {
|
||||
// write code to save file to SharePoint doc library
|
||||
// if you are uploading the file via the upload tab which I've not implemented here
|
||||
onUpdate(field.id, filePickerResult);
|
||||
return Event;
|
||||
},
|
||||
onSave: (filePickerResult: IFilePickerResult[]) => {
|
||||
// write code to save file to SharePoint doc library
|
||||
// if you are uploading the file via the upload tab which I've not implemented here
|
||||
onUpdate(field.id, filePickerResult);
|
||||
return Event;
|
||||
},
|
||||
hideLocalUploadTab: true,
|
||||
hideLocalMultipleUploadTab: true,
|
||||
hideLinkUploadTab: true
|
||||
})
|
||||
);
|
||||
}
|
||||
},
|
||||
hideLocalUploadTab: true,
|
||||
hideLocalMultipleUploadTab: true,
|
||||
hideLinkUploadTab: true
|
||||
})
|
||||
);
|
||||
},
|
||||
required: true
|
||||
}
|
||||
],
|
||||
disabled: false
|
||||
|
|
|
@ -11,12 +11,15 @@ export default class Hero extends React.Component<IHeroLayoutProps> {
|
|||
|
||||
|
||||
public render(): React.ReactElement<IHeroLayoutProps> {
|
||||
//const classTotal = "itemShow"+this.props.totalShow;
|
||||
const items = this.props.items;
|
||||
const viewType = items.length==1 ? "heroOne" : items.length==2 ? "heroTwo" : items.length==3 ? "heroThree" :
|
||||
items.length==4 ? "heroFour" : items.length==5 ? "heroFive" : "heroFive";
|
||||
var arr = [];
|
||||
arr.push(items);
|
||||
|
||||
return (
|
||||
<div role="group">
|
||||
<div role="group" className={viewType}>
|
||||
<List
|
||||
role="presentation"
|
||||
className={styles.heroItem}
|
||||
|
@ -37,7 +40,7 @@ export default class Hero extends React.Component<IHeroLayoutProps> {
|
|||
const thumbRend = "https://media.akamai.odsp.cdn.office.net/uksouth1-mediap.svc.ms/transform/thumbnail?provider=url&inputFormat=jpg&docid=";
|
||||
const secondItems = items.slice(1,5);
|
||||
const firstItem = items.slice(0,1)[0];
|
||||
var firstItemUrl = firstItem.filePicker[0].Hyperlink ? firstItem.filePicker[0].Hyperlink : "#";
|
||||
var firstItemUrl = firstItem.Hyperlink ? firstItem.Hyperlink : "#";
|
||||
var smalltemUrl;
|
||||
return(
|
||||
<div className={styles.heroItem}>
|
||||
|
@ -46,18 +49,20 @@ export default class Hero extends React.Component<IHeroLayoutProps> {
|
|||
<div className={styles["flexitems"]}>
|
||||
<a href={firstItemUrl}>
|
||||
<img src={firstItem.filePicker[0].fileNameWithoutExtension=='blankEntry154873'?firstItem.filePicker[0].fileAbsoluteUrl:thumbRend+firstItem.filePicker[0].fileAbsoluteUrl+"&w=960"}/>
|
||||
<div className={styles.description}><div className={styles.heroTitle}>{firstItem.Title}</div>{firstItem.Description ? firstItem.Description.length>150 ? firstItem.Description.substring(0, 150)+".." : firstItem.Description : "Description coming soon"}</div>
|
||||
<div className={styles.heroTitle}>{firstItem.Title}</div>
|
||||
<div className={styles.description}><div className={styles.heroTitleHover}>{firstItem.Title}</div><div className={styles.info}>{firstItem.Description ? firstItem.Description.length>150 ? firstItem.Description.substring(0, 150)+".." : firstItem.Description : "Description coming soon"}</div></div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles["flexcontainer"]}>
|
||||
{secondItems.map((item) => (
|
||||
smalltemUrl= item.filePicker[0].Hyperlink ? item.filePicker[0].Hyperlink : "#",
|
||||
smalltemUrl= item.Hyperlink ? item.Hyperlink : "#",
|
||||
<div className={styles["flexitems"]}>
|
||||
<a href={smalltemUrl}>
|
||||
<img src={item.filePicker[0].fileNameWithoutExtension=='blankEntry154873'?item.filePicker[0].fileAbsoluteUrl:thumbRend+item.filePicker[0].fileAbsoluteUrl+"&w=960"}/>
|
||||
<div className={styles.description}><div className={styles.heroTitle}>{item.Title}</div>{item.Description ? item.Description.length>150 ? item.Description.substring(0, 150)+".." : item.Description : "Description coming soon"}</div>
|
||||
<div className={styles.heroTitle}>{item.Title}</div>
|
||||
<div className={styles.description}><div className={styles.heroTitleHover}>{item.Title}</div><div className={styles.info}>{item.Description ? item.Description.length>150 ? item.Description.substring(0, 150)+".." : item.Description : "Description coming soon"}</div></div>
|
||||
</a>
|
||||
</div>
|
||||
))}
|
||||
|
|
|
@ -72,91 +72,62 @@
|
|||
}
|
||||
}
|
||||
|
||||
.carouselContent{
|
||||
color:"[theme: themeSecondary, default: #0078d7]";
|
||||
min-height:600px;
|
||||
height:600px;
|
||||
}
|
||||
.carouselButtonsContainer{
|
||||
color:"[theme: themeSecondary, default: #0078d7]";
|
||||
}
|
||||
|
||||
.carouselContentOne, .carouselContentTwo, .carouselContentThree, .carouselContentFour{
|
||||
color:"[theme: themeSecondary, default: #0078d7]";
|
||||
min-height:530px;
|
||||
height:530px;
|
||||
}
|
||||
|
||||
.carouselContentOne{
|
||||
:global(.ms-List-page .ms-List-cell){
|
||||
width: 100%!important;
|
||||
padding:0%
|
||||
}
|
||||
:global(.ms-List-page .ms-List-cell div) {
|
||||
width: 100%!important;
|
||||
}
|
||||
}
|
||||
|
||||
.carouselContentTwo {
|
||||
:global(.ms-List-page .ms-List-cell){
|
||||
width: 46%!important;
|
||||
padding:2%
|
||||
}
|
||||
:global(.ms-List-page .ms-List-cell div) {
|
||||
width: 100%!important;
|
||||
}
|
||||
}
|
||||
|
||||
.carouselContentThree{
|
||||
:global(.ms-List-page .ms-List-cell){
|
||||
width: 29%!important;
|
||||
padding:2%
|
||||
}
|
||||
:global(.ms-List-page .ms-List-cell div) {
|
||||
width: 100%!important;
|
||||
}
|
||||
}
|
||||
|
||||
.carouselContentFour{
|
||||
:global(.ms-List-page .ms-List-cell){
|
||||
width: 24%!important;
|
||||
padding:1%
|
||||
}
|
||||
:global(.ms-List-page .ms-List-cell div) {
|
||||
width: 100%!important;
|
||||
}
|
||||
}
|
||||
|
||||
.heroTitle{
|
||||
.heroTitleHover{
|
||||
@include ms-font-xl;
|
||||
padding-bottom: 10px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.heroTitle{
|
||||
@include ms-fontColor-white;
|
||||
font-size: 26px;
|
||||
font-weight: 600;
|
||||
position: absolute;
|
||||
bottom: 5px;
|
||||
width: 100%;
|
||||
padding: 30px 0px;;
|
||||
text-align: center;
|
||||
background-image: linear-gradient(180deg,transparent 15%,rgba(0,0,0,.7));
|
||||
height: fit-content!important;
|
||||
}
|
||||
|
||||
.info,.heroTitleHover{
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.heroItem {
|
||||
flex: auto;
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
|
||||
.flexcontainer .flexitems:hover img{
|
||||
transform: scale(1.1);
|
||||
transition: .4s ease;
|
||||
}
|
||||
|
||||
.flexcontainer .flexitems:hover .heroTitle{
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.flexcontainer .flexitems:hover .description {
|
||||
opacity: 1;
|
||||
background: rgba(0, 0, 0, 0.9);
|
||||
.info,.heroTitleHover{
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.flexcontainer .flexitems .description{
|
||||
@include ms-fontColor-white;
|
||||
position: absolute;
|
||||
bottom: 5px;
|
||||
background: rgba(0, 0, 0, 0.9);
|
||||
color: #f1f1f1;
|
||||
width: calc(100% - 40px);
|
||||
transition: .5s ease;
|
||||
opacity: 0;
|
||||
color: white;
|
||||
font-size: 16px;
|
||||
padding: 20px 0px;;
|
||||
text-align: center;
|
||||
}
|
||||
@include ms-fontColor-white;
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
background: rgba(0, 0, 0, 0);
|
||||
width: calc(100% - 40px);
|
||||
transition: .5s ease;
|
||||
font-size: 18px;
|
||||
padding: 20px 0px;;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.flexcontainer .flexitems{
|
||||
overflow: hidden;
|
||||
|
@ -164,10 +135,14 @@
|
|||
|
||||
.flexcontainer:nth-child(1){
|
||||
flex: auto;
|
||||
flex-basis: 40%;
|
||||
flex-basis: 50%;
|
||||
flex-shrink: 1;
|
||||
padding-right:5px;
|
||||
padding-bottom: 7px;
|
||||
padding-bottom: 5px;
|
||||
|
||||
.heroTitle{
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
*{
|
||||
height: 100%;
|
||||
|
@ -201,34 +176,116 @@
|
|||
|
||||
.flexcontainer:nth-child(2) {
|
||||
flex: auto;
|
||||
flex-basis: 60%;
|
||||
flex-basis: 50%;
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.heroTitle{
|
||||
width: calc(100% - 5px);
|
||||
}
|
||||
|
||||
img{
|
||||
width:100%;
|
||||
height:100%;
|
||||
}
|
||||
|
||||
.description {
|
||||
width: calc(100% - 5px);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.flexitems{
|
||||
padding-right:5px;
|
||||
flex-basis: calc(50% - 5px);
|
||||
flex-shrink: 1;
|
||||
flex-grow: 1;
|
||||
align-self: auto;
|
||||
position: relative;
|
||||
padding-bottom: 5px;
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
.flexitems:hover{
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
:global(.heroThree) .heroItem {
|
||||
.flexcontainer:nth-child(1){
|
||||
flex-basis: 60%;
|
||||
.focusItem .flexitems{
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
}
|
||||
.flexcontainer:nth-child(2)
|
||||
{
|
||||
flex-basis: 40%;
|
||||
.flexitems {
|
||||
flex-basis: 50%;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:global(.heroFive) .heroItem {
|
||||
.flexcontainer:nth-child(1){
|
||||
min-height: 400px;
|
||||
}
|
||||
}
|
||||
|
||||
:global(.heroOne) .heroItem {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
.flexcontainer:nth-child(1){
|
||||
min-height: 400px;
|
||||
.focusItem .flexitems{
|
||||
max-height: 400px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:global(.heroThree) .heroItem .flexcontainer:nth-child(2) {
|
||||
.heroTitle {
|
||||
font-size: 24px;
|
||||
}
|
||||
.heroTitleHover{
|
||||
font-size: 22px;
|
||||
}
|
||||
.info{
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
:global(.heroFour) .heroItem .flexcontainer:nth-child(2){
|
||||
.heroTitle {
|
||||
font-size: 20px;
|
||||
}
|
||||
.heroTitleHover{
|
||||
font-size: 18px;
|
||||
}
|
||||
.info{
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
:global(.heroFive) .heroItem .flexcontainer:nth-child(2){
|
||||
.heroTitle {
|
||||
font-size: 20px;
|
||||
}
|
||||
.heroTitleHover{
|
||||
font-size: 18px;
|
||||
}
|
||||
.info{
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@media all and (max-width: 768px) {
|
||||
.heroItem {
|
||||
flex-direction: column;
|
||||
|
@ -240,55 +297,4 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 600px) {
|
||||
.carouselContentOne, .carouselContentTwo, .carouselContentThree, .carouselContentFour{
|
||||
:global(.ms-List-page .ms-List-cell){
|
||||
width: 100%!important;
|
||||
height: 160px;
|
||||
}
|
||||
:global(.ms-List-page .ms-List-cell img){
|
||||
width: 100%!important;
|
||||
height: 100px!important;
|
||||
}
|
||||
:global(.ms-List-page .ms-List-cell .ms-Image){
|
||||
width: 100%!important;
|
||||
height: 100px!important;
|
||||
}
|
||||
:global(.ms-List-page .ms-List-cell div){
|
||||
max-height: 100px;
|
||||
}
|
||||
:global(.ms-List-page .ms-List-cell div){
|
||||
max-height: 100px;
|
||||
}
|
||||
:global(.ms-List-page .ms-List-cell .ms-DocumentCardLocation){
|
||||
display:none;
|
||||
}
|
||||
:global(.ms-List-page .ms-List-cell){
|
||||
.subGroup{
|
||||
display:none;
|
||||
}
|
||||
}
|
||||
:global(.ms-List-page .ms-List-cell){
|
||||
.subGroup ~ .subGroup{
|
||||
display:inline-block;
|
||||
}
|
||||
}
|
||||
:global(.ms-List-page .ms-List-cell){
|
||||
.subGroup ~ .subGroup a{
|
||||
display:inline-block;
|
||||
width: 48%!important;
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
:global(.ms-List-page .ms-List-cell){
|
||||
.subGroup ~ .subGroup a *{
|
||||
font-size:8px
|
||||
}
|
||||
}
|
||||
:global(.ms-List-page .ms-List-cell .ms-DocumentCardDetails .ms-DocumentCardTitle:nth-child(2)){
|
||||
display:none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,10 +2,7 @@ import * as React from 'react';
|
|||
import styles from './HeroWebpart.module.scss';
|
||||
import { IHeroWebpartProps } from './IHeroWebpartProps';
|
||||
import {IHeroState} from './IHeroWebpartState';
|
||||
import { escape } from '@microsoft/sp-lodash-subset';
|
||||
import { Pagination } from "@pnp/spfx-controls-react/lib/pagination";
|
||||
import { PnPClientStorage } from "@pnp/common";
|
||||
import { IHeroLayoutProps } from './IHeroLayoutProps';
|
||||
import Hero from './HeroLayout';
|
||||
import { sp } from '@pnp/sp';
|
||||
import { Stack, IStackProps, IStackTokens } from 'office-ui-fabric-react/lib/Stack';
|
||||
|
@ -25,8 +22,6 @@ const tokens = {
|
|||
},
|
||||
};
|
||||
|
||||
const storage = new PnPClientStorage();
|
||||
|
||||
export default class HeroWebpart extends React.Component<IHeroWebpartProps, IHeroState> {
|
||||
|
||||
constructor(props: IHeroWebpartProps) {
|
||||
|
@ -73,6 +68,18 @@ export default class HeroWebpart extends React.Component<IHeroWebpartProps, IHer
|
|||
return b;
|
||||
}
|
||||
|
||||
public componentDidUpdate(prevProps : IHeroWebpartProps, prevState : IHeroState) : void
|
||||
{
|
||||
// If properties have changed bind it and update webpart
|
||||
if(this.props.items !== prevProps.items)
|
||||
{
|
||||
this.setState({items:this.props.items});
|
||||
if(this.props.showAllHero){
|
||||
this._getPage(this.state.currentPage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public render(): React.ReactElement<IHeroWebpartProps> {
|
||||
if(this.state.items.length<=0){
|
||||
this._getItems();
|
||||
|
|
Loading…
Reference in New Issue