Merge pull request #1765 from joaojmendes/master

This commit is contained in:
Hugo Bernier 2021-03-11 00:56:55 -05:00 committed by GitHub
commit 329f20d196
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 185 additions and 33 deletions

View File

@ -23,6 +23,8 @@ extensions:
This web part shows the current user's colleagues, and allows the user to search AD directory, The user can configure the properties to show when expand the user card. This web part shows the current user's colleagues, and allows the user to search AD directory, The user can configure the properties to show when expand the user card.
![staff](./assets/staffdirectory.gif) ![staff](./assets/staffdirectory.gif)
![staff](./assets/staffTeams01.png)
![staff](./assets/staffTeams02.png)
## Compatibility ## Compatibility

Binary file not shown.

After

Width:  |  Height:  |  Size: 484 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 446 KiB

View File

@ -49,7 +49,7 @@
"jest": "^23.6.0", "jest": "^23.6.0",
"jest-junit": "^10.0.0", "jest-junit": "^10.0.0",
"lodash": "^4.17.15", "lodash": "^4.17.15",
"spfx-uifabric-themes": "^0.8.0", "spfx-uifabric-themes": "^0.8.5",
"typescript": "~3.7.x" "typescript": "~3.7.x"
}, },
"jest-junit": { "jest-junit": {

View File

@ -0,0 +1,24 @@
{
"themePrimary": "#6264a7",
"themeLighterAlt": "#f7f7fb",
"themeLighter": "#e1e1f1",
"themeLight": "#c8c9e4",
"themeTertiary": "#989ac9",
"themeSecondary": "#7173b0",
"themeDarkAlt": "#585a95",
"themeDark": "#4a4c7e",
"themeDarker": "#37385d",
"neutralLighterAlt": "#0b0b0b",
"neutralLighter": "#151515",
"neutralLight": "#252525",
"neutralQuaternaryAlt": "#2f2f2f",
"neutralQuaternary": "#373737",
"neutralTertiaryAlt": "#595959",
"neutralTertiary": "#c8c8c8",
"neutralSecondary": "#d0d0d0",
"neutralPrimaryAlt": "#dadada",
"neutralPrimary": "#ffffff",
"neutralDark": "#f4f4f4",
"black": "#f8f8f8",
"white": "#000000"
}

View File

@ -0,0 +1,24 @@
{
"themePrimary": "#6264a7",
"themeLighterAlt": "#f7f7fb",
"themeLighter": "#e1e1f1",
"themeLight": "#c8c9e4",
"themeTertiary": "#989ac9",
"themeSecondary": "#7173b0",
"themeDarkAlt": "#585a95",
"themeDark": "#4a4c7e",
"themeDarker": "#37385d",
"neutralLighterAlt": "#2d2c2c",
"neutralLighter": "#2c2b2b",
"neutralLight": "#2a2929",
"neutralQuaternaryAlt": "#272626",
"neutralQuaternary": "#252525",
"neutralTertiaryAlt": "#242323",
"neutralTertiary": "#c8c8c8",
"neutralSecondary": "#d0d0d0",
"neutralPrimaryAlt": "#dadada",
"neutralPrimary": "#ffffff",
"neutralDark": "#f4f4f4",
"black": "#f8f8f8",
"white": "#2d2c2c"
}

View File

@ -0,0 +1,24 @@
{
"themePrimary": "#6264a7",
"themeLighterAlt": "#f7f7fb",
"themeLighter": "#e1e1f1",
"themeLight": "#c8c9e4",
"themeTertiary": "#989ac9",
"themeSecondary": "#7173b0",
"themeDarkAlt": "#585a95",
"themeDark": "#4a4c7e",
"themeDarker": "#37385d",
"neutralLighterAlt": "#ecebe9",
"neutralLighter": "#e8e7e6",
"neutralLight": "#dedddc",
"neutralQuaternaryAlt": "#cfcecd",
"neutralQuaternary": "#c6c5c4",
"neutralTertiaryAlt": "#bebdbc",
"neutralTertiary": "#b5b4b2",
"neutralSecondary": "#9d9c9a",
"neutralPrimaryAlt": "#868482",
"neutralPrimary": "#252423",
"neutralDark": "#565453",
"black": "#3e3d3b",
"white": "#f3f2f1"
}

View File

@ -0,0 +1,17 @@
$default-background: #f3f2f1;
$default-color: #252423;
$default-button-background: #6264a7;
$default-Button-color: #f3f2f1;
// dark theme
$dark-background: #2d2c2c;
$dark-color: #ffffff;
$dark-button-background: #6264a7;
$dark-button-color: #2d2c2c;
// contrast theme
$contrast-background: #000000;
$contrast-color: #ffffff;
$contrast-button-background: #b5c01c;
$contrast-Button-color: #000000;

View File

@ -46,7 +46,7 @@ import { AppContext } from "../../common/AppContext";
import { UserCard } from "../UserCard/UserCard"; import { UserCard } from "../UserCard/UserCard";
import { useRef } from "react"; import { useRef } from "react";
import strings from "StaffDirectoryWebPartStrings"; import strings from "StaffDirectoryWebPartStrings";
import {Theme} from 'spfx-uifabric-themes';
const imageNoData: string = require("../../../assets/Nodatarafiki.svg"); const imageNoData: string = require("../../../assets/Nodatarafiki.svg");
@ -73,7 +73,7 @@ export const StaffDirectory: React.FunctionComponent<IStaffDirectoryProps> = (
props: IStaffDirectoryProps props: IStaffDirectoryProps
) => { ) => {
const { showBox, maxHeight } = props; const { showBox, maxHeight } = props;
const _theme = window.__themeState__.theme;
const styleClasses = mergeStyleSets({ const styleClasses = mergeStyleSets({
webPartTitle: { webPartTitle: {
marginBottom: 20, marginBottom: 20,
@ -85,7 +85,7 @@ export const StaffDirectory: React.FunctionComponent<IStaffDirectoryProps> = (
margin: 20, margin: 20,
borderBottomStyle: "solid", borderBottomStyle: "solid",
borderWidth: 1, borderWidth: 1,
borderBottomColor: props.themeVariant.palette.themeLighter, borderBottomColor: props.themeVariant?.palette?.themeLighter ?? _theme.themeLighter,
}, },
styleIcon: { styleIcon: {
@ -93,7 +93,7 @@ export const StaffDirectory: React.FunctionComponent<IStaffDirectoryProps> = (
minWidth: 44, minWidth: 44,
minHeight: 30, minHeight: 30,
height: 30, height: 30,
borderColor: props.themeVariant.palette.themePrimary, borderColor: props.themeVariant?.palette?.themePrimary ?? _theme.themePrimary,
borderRightWidth: 0, borderRightWidth: 0,
borderRightStyle: "none", borderRightStyle: "none",
borderLeftWidth: 1, borderLeftWidth: 1,
@ -123,24 +123,24 @@ export const StaffDirectory: React.FunctionComponent<IStaffDirectoryProps> = (
width: "100%", width: "100%",
maxHeight: 32, maxHeight: 32,
minHeight: 32, minHeight: 32,
borderColor: props.themeVariant.palette.themePrimary, borderColor: props.themeVariant?.palette?.themePrimary ?? _theme.themePrimary,
}, },
itemsWrapper: { itemsWrapper: {
borderColor: props.themeVariant.palette.themePrimary, borderColor: props.themeVariant?.palette?.themePrimary ?? _theme.themePrimary,
}, },
text: { text: {
borderLeftWidth: 0, borderLeftWidth: 0,
minHeight: 32, minHeight: 32,
borderColor: props.themeVariant.palette.themePrimary, borderColor: props.themeVariant?.palette?.themePrimary ?? _theme.themePrimary,
selectors: { selectors: {
":focus": { ":focus": {
borderColor: props.themeVariant.palette.themePrimary, borderColor:props.themeVariant?.palette?.themePrimary ?? _theme.themePrimary,
}, },
":hover": { ":hover": {
borderColor: props.themeVariant.palette.themePrimary, borderColor: props.themeVariant?.palette?.themePrimary ?? _theme.themePrimary,
}, },
"::after": { "::after": {
borderColor: props.themeVariant.palette.themePrimary, borderColor: props.themeVariant?.palette?.themePrimary ?? _theme.themePrimary,
borderWidth: 1, borderWidth: 1,
borderLeftWidth: 0, borderLeftWidth: 0,
}, },
@ -151,7 +151,7 @@ export const StaffDirectory: React.FunctionComponent<IStaffDirectoryProps> = (
const nextPageStyle: ILinkStyles = { const nextPageStyle: ILinkStyles = {
root: { root: {
fontWeight: 600, fontWeight: 600,
fontSize: props.themeVariant.fonts.mediumPlus.fontSize, fontSize: props.themeVariant?.fonts?.mediumPlus?.fontSize ?? window.__themeState__.theme["ms-font-mediumPlus-fontSize"],
selectors: { ":hover": { textDecoration: "underline" } }, selectors: { ":hover": { textDecoration: "underline" } },
}, },
}; };
@ -383,8 +383,8 @@ export const StaffDirectory: React.FunctionComponent<IStaffDirectoryProps> = (
iconName="Search" iconName="Search"
style={{ style={{
verticalAlign: "center", verticalAlign: "center",
fontSize: props.themeVariant.fonts.mediumPlus.fontSize, fontSize: props.themeVariant?.fonts?.mediumPlus?.fontSize ?? window.__themeState__.theme["ms-font-mediumPlus-fontSize"],
color: props.themeVariant.palette.themePrimary, color: props.themeVariant?.palette.themePrimary ?? _theme.themePrimary,
}} }}
/> />
</div> </div>

View File

@ -10,6 +10,7 @@ import {
Link, Link,
ITextFieldStyles, ITextFieldStyles,
IPersonaProps, IPersonaProps,
loadTheme,
} from "office-ui-fabric-react"; } from "office-ui-fabric-react";
import { presenceStatus, IPresenceStatus } from "../../common/PresenceStatus"; import { presenceStatus, IPresenceStatus } from "../../common/PresenceStatus";
import { AppContext } from "../../common/AppContext"; import { AppContext } from "../../common/AppContext";
@ -18,14 +19,19 @@ import { IUserExtended } from "../../entites/IUserExtended";
import { IAppContext } from "../../common/IAppContext"; import { IAppContext } from "../../common/IAppContext";
import { IUserCardProps } from "./IUserCardProps"; import { IUserCardProps } from "./IUserCardProps";
const teamsDefaultTheme = require("../../common/TeamsDefaultTheme.json");
const teamsDarkTheme = require("../../common/TeamsDarkTheme.json");
const teamsContrastTheme = require("../../common/TeamsContrastTheme.json");
export const UserCard = (props: IUserCardProps) => { export const UserCard = (props: IUserCardProps) => {
const { userData, updateUsersPresence } = props; const { userData, updateUsersPresence } = props;
const _context: IAppContext = React.useContext(AppContext); const _context: IAppContext = React.useContext(AppContext);
const [expandIcon, setExpandIcon] = React.useState("ChevronDownSmall"); const [expandIcon, setExpandIcon] = React.useState("ChevronDownSmall");
const [isDetailsOpen, setIsDetailsOpen] = React.useState(false); const [isDetailsOpen, setIsDetailsOpen] = React.useState(false);
const _Theme = window.__themeState__.theme;
const styleClasses = mergeStyleSets({ const styleClasses = mergeStyleSets({
separator: { separator: {
marginLeft: 20, marginLeft: 20,
@ -33,31 +39,32 @@ export const UserCard = (props: IUserCardProps) => {
marginTop: 15, marginTop: 15,
borderBottomStyle: "solid", borderBottomStyle: "solid",
borderWidth: 1, borderWidth: 1,
borderBottomColor: _context.themeVariant.palette.neutralLighterAlt, borderBottomColor: _context.themeVariant?.palette?.themeLighter ?? _Theme.themeLighter,
}, },
stylContainerDetails: { stylContainerDetails: {
marginTop: 25, marginTop: 25,
display: "grid", display: "grid",
justifyContent: "stretch", justifyContent: "stretch",
alignItems: "center", alignItems: "center",
backgroundColor: _context.themeVariant.palette.themeLighter, backgroundColor: _context.themeVariant?.palette?.neutralLighterAlt ?? _Theme.neutralLighterAlt,
gridTemplateColumns: "repeat( auto-fit, minmax(280px, 1fr) )", gridTemplateColumns: "repeat( auto-fit, minmax(280px, 1fr) )",
gridTemplateRows: "auto", gridTemplateRows: "auto",
}, },
styleIconDetails: { styleIconDetails: {
fontSize: 16, fontSize: 16,
color: _context.themeVariant.palette.themePrimary, color: _context.themeVariant?.palette?.themePrimary ?? _Theme.themePrimary,
}, },
styleFieldLabel: { styleFieldLabel: {
fontSize: 12, fontSize: 12,
fontWeight: 400, fontWeight: 400,
paddingLeft: 3, paddingLeft: 3,
color: _Theme.inputText
}, },
styleField: { styleField: {
paddingTop: 15, paddingTop: 15,
color: _context.themeVariant?.palette?.themePrimary ?? _Theme.themePrimary,
}, },
}); });
@ -127,12 +134,12 @@ export const UserCard = (props: IUserCardProps) => {
root: { root: {
height: 21, height: 21,
width: 26, width: 26,
color: _context.themeVariant.palette.themePrimary, color: _context.themeVariant?.palette?.themeSecondary ?? _Theme.themeSecondary,
}, },
}} }}
iconProps={{ iconProps={{
iconName: "CannedChat", iconName: "CannedChat",
color: _context.themeVariant.palette.themePrimary, color: _context.themeVariant?.palette?.themeSecondary ??_Theme.themeSecondary,
}} }}
allowDisabledFocus={true} allowDisabledFocus={true}
disabled={false} disabled={false}
@ -156,12 +163,13 @@ export const UserCard = (props: IUserCardProps) => {
root: { root: {
height: 21, height: 21,
width: 26, width: 26,
color: _context.themeVariant.palette.themePrimary,
}, },
}} }}
iconProps={{ iconProps={{
iconName: expandIcon, iconName: expandIcon,
color: _context.themeVariant.palette.themePrimary, color: _Theme.themeSecondary
}} }}
allowDisabledFocus={true} allowDisabledFocus={true}
disabled={false} disabled={false}

View File

@ -13,7 +13,7 @@
// Components that allow authors to embed arbitrary script code should set this to true. // 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 // https://support.office.com/en-us/article/Turn-scripting-capabilities-on-or-off-1f2c515f-5d7e-448a-9fd7-835da935584f
"requiresCustomScript": false, "requiresCustomScript": false,
"supportedHosts": ["SharePointWebPart"], "supportedHosts": ["SharePointWebPart","TeamsTab","TeamsPersonalApp"],
"preconfiguredEntries": [{ "preconfiguredEntries": [{
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other "groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other

View File

@ -6,16 +6,19 @@ import {
PropertyPaneTextField, PropertyPaneTextField,
PropertyPaneSlider, PropertyPaneSlider,
PropertyPaneToggle, PropertyPaneToggle,
PropertyPaneHorizontalRule PropertyPaneHorizontalRule,
PropertyPaneLabel,
PopupWindowPosition
} from '@microsoft/sp-property-pane'; } from '@microsoft/sp-property-pane';
import { BaseClientSideWebPart, PropertyPaneLabel } from '@microsoft/sp-webpart-base'; import { BaseClientSideWebPart, } from '@microsoft/sp-webpart-base';
import * as strings from 'StaffDirectoryWebPartStrings'; import * as strings from 'StaffDirectoryWebPartStrings';
import {StaffDirectory} from '../../components/StaffDirectory/StaffDirectory'; import {StaffDirectory} from '../../components/StaffDirectory/StaffDirectory';
import { IStaffDirectoryProps } from '../../components/StaffDirectory/IStaffDirectoryProps'; import { IStaffDirectoryProps } from '../../components/StaffDirectory/IStaffDirectoryProps';
import { PropertyFieldMultiSelect } from '@pnp/spfx-property-controls/lib/PropertyFieldMultiSelect'; import { PropertyFieldMultiSelect } from '@pnp/spfx-property-controls/lib/PropertyFieldMultiSelect';
import {Theme} from 'spfx-uifabric-themes';
import { ThemeProvider, ThemeChangedEventArgs, IReadonlyTheme } from '@microsoft/sp-component-base'; import { ThemeProvider, ThemeChangedEventArgs, IReadonlyTheme } from '@microsoft/sp-component-base';
import { loadTheme } from 'office-ui-fabric-react';
export interface IStaffDirectoryWebPartProps { export interface IStaffDirectoryWebPartProps {
title: string; title: string;
maxHeight: number; maxHeight: number;
@ -28,27 +31,77 @@ export interface IStaffDirectoryWebPartProps {
pageSize:number; pageSize:number;
} }
const teamsDefaultTheme = require("../../common/TeamsDefaultTheme.json");
const teamsDarkTheme = require("../../common/TeamsDarkTheme.json");
const teamsContrastTheme = require("../../common/TeamsContrastTheme.json");
export default class StaffDirectoryWebPart extends BaseClientSideWebPart<IStaffDirectoryWebPartProps> { export default class StaffDirectoryWebPart extends BaseClientSideWebPart<IStaffDirectoryWebPartProps> {
private _themeProvider: ThemeProvider; private _themeProvider: ThemeProvider;
private _themeVariant: IReadonlyTheme | undefined; private _themeVariant: IReadonlyTheme | undefined;
protected async onInit(): Promise<void> { protected async onInit(): Promise<void> {
window.sessionStorage.clear();
this._themeProvider = this.context.serviceScope.consume(ThemeProvider.serviceKey);
this._themeProvider = this.context.serviceScope.consume(
ThemeProvider.serviceKey
);
// If it exists, get the theme variant // If it exists, get the theme variant
this._themeVariant = this._themeProvider.tryGetTheme(); this._themeVariant = this._themeProvider.tryGetTheme();
// Register a handler to be notified if the theme variant changes // Register a handler to be notified if the theme variant changes
this._themeProvider.themeChangedEvent.add(this, this._handleThemeChangedEvent); this._themeProvider.themeChangedEvent.add(
this,
this._handleThemeChangedEvent
);
if (this.context.sdks.microsoftTeams) {
// in teams ?
const context = this.context.sdks.microsoftTeams!.context;
this._applyTheme(context.theme || "default");
this.context.sdks.microsoftTeams.teamsJs.registerOnThemeChangeHandler(
this._applyTheme
);
}
return Promise.resolve(); return Promise.resolve();
} }
/**
* Update the current theme variant reference and re-render.
*
* @param args The new theme
*/
private _handleThemeChangedEvent(args: ThemeChangedEventArgs): void { private _handleThemeChangedEvent(args: ThemeChangedEventArgs): void {
this._themeVariant = args.theme; this._themeVariant = args.theme;
this.render(); this.render();
} }
// Apply btheme id in Teams
private _applyTheme = (theme: string): void => {
this.context.domElement.setAttribute("data-theme", theme);
document.body.setAttribute("data-theme", theme);
if (theme == "dark") {
loadTheme({
palette: teamsDarkTheme,
});
}
if (theme == "default") {
loadTheme({
palette: teamsDefaultTheme,
});
}
if (theme == "contrast") {
loadTheme({
palette: teamsContrastTheme,
});
}
this.render();
}
public render(): void { public render(): void {
const element: React.ReactElement<IStaffDirectoryProps> = React.createElement( const element: React.ReactElement<IStaffDirectoryProps> = React.createElement(
@ -58,7 +111,7 @@ export default class StaffDirectoryWebPart extends BaseClientSideWebPart<IStaffD
context: this.context, context: this.context,
maxHeight: this.properties.maxHeight, maxHeight: this.properties.maxHeight,
showBox: this.properties.showBox, showBox: this.properties.showBox,
themeVariant: this._themeVariant, themeVariant: this._themeVariant ,
displayMode: this.displayMode, displayMode: this.displayMode,
updateProperty: (value:string ) => { updateProperty: (value:string ) => {
this.properties.title = value; this.properties.title = value;