Skip to content

Commit 107cf0a

Browse files
authored
Merge pull request #1243 from mmsharepoint/audio
New Modern Audio control
2 parents 3620c0f + 090882b commit 107cf0a

File tree

15 files changed

+194
-3
lines changed

15 files changed

+194
-3
lines changed
3.73 KB
Loading
3.7 KB
Loading
66.3 KB
Loading
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Modern Audio
2+
3+
This control renders an Audio Control in a modern and themable way. It is controllable with Fluent UI icons instead of old-fashioned standard HTML5 Audio control.
4+
5+
!!! Note
6+
Originally it's coming from the following community [Teams app sample](https://github.com/pnp/teams-dev-samples/tree/main/samples/tab-meeting-record-name).
7+
8+
**Modern Audio control rendered with label and default label positioning**
9+
10+
![Modern Audio](../assets/ModernAudioDefault.png)
11+
12+
**Modern Audio control rendered with dark (lime) theme and label positioned BottomLeft**
13+
14+
![Modern Audio dark](../assets/ModernAudioDarkLime.png)
15+
16+
**Modern Audio control in action with label positioned at BottomCenter**
17+
18+
![Modern Audio in action](../assets/ModernAudioInAction.gif)
19+
20+
## How to use this control in your solutions
21+
22+
- Check that you installed the `@pnp/spfx-controls-react` dependency. Check out the [getting started](../../#getting-started) page for more information about installing the dependency.
23+
- Import the following modules to your component:
24+
25+
```typescript
26+
import { ModernAudio, ModernAudioLabelPosition } from "@pnp/spfx-controls-react/lib/ModernAudio";
27+
```
28+
29+
- Use the `ModernAudio` control in your code as follows:
30+
31+
```typescript
32+
<ModernAudio
33+
audioUrl='https://www.winhistory.de/more/winstart/mp3/vista.mp3'
34+
label="Audio Control"
35+
labelPosition={ModernAudioLabelPosition.TopCenter} />
36+
```
37+
38+
39+
## Implementation
40+
41+
The Modern Audio control can be configured with the following properties:
42+
43+
| Property | Type | Required | Description | Default |
44+
| ---- | ---- | ---- | ---- | ---- |
45+
| audioUrl | string | yes | Url to the audio src | |
46+
| label | string | no | Label to use for the control. | blank |
47+
| labelPosition | ModernAudioLabelPosition | no | Define position of label: TopLeft, TopCenter, BottomLeft, BottomCenter. | TopLeft |
48+
49+
Enum `ModernAudioLabelPosition`
50+
51+
The `ModernAudioLabelPosition` enum can be used to specify the types of information you want to query: User, Security groups, and/or SharePoint groups.
52+
53+
| Name | Value | Position
54+
| ---- | ---- | ---- |
55+
| TopLeft | 1 | On top, left aligned
56+
| TopCenter | 2 | On top, centered
57+
| BottomLeft | 3 | At bottom, left aligned
58+
| BottomCenter | 4 | At bottom, centered
59+
60+
61+
![](https://telemetry.sharepointpnp.com/sp-dev-fx-controls-react/wiki/controls/ModernAudio)
62+

src/ModernAudio.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './controls/modernAudio/index';
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { ModernAudioLabelPosition } from "./ModernAudioLabelPosition";
2+
3+
export interface IModernAudioProps {
4+
audioUrl: string;
5+
label?: string;
6+
labelPosition?: ModernAudioLabelPosition;
7+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.modernAudio {
2+
display: table-cell;
3+
padding: 8px;
4+
.audioPanel {
5+
border: 1px dotted;
6+
border-radius: 8px;
7+
padding: 8px;
8+
display: inline-block;
9+
}
10+
.audioIcon {
11+
cursor: pointer;
12+
}
13+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import * as React from "react";
2+
import styles from './ModernAudio.module.scss';
3+
import * as strings from 'ControlStrings';
4+
import { IModernAudioProps } from "./IModernAudioProps";
5+
import { IconButton } from "office-ui-fabric-react";
6+
import { ModernAudioLabelPosition } from './ModernAudioLabelPosition';
7+
8+
export const ModernAudio: React.FC<IModernAudioProps> = (props: IModernAudioProps) => {
9+
const audioComp = React.useRef<HTMLAudioElement>(new Audio(props.audioUrl));
10+
const [muted, setMuted] = React.useState<boolean>(false);
11+
const [playing, setPlaying] = React.useState<boolean>(false);
12+
13+
React.useEffect(() => {
14+
audioComp.current.onended = () => { setPlaying(false); };
15+
}, []);
16+
17+
const playAudio = () => {
18+
setPlaying(true);
19+
audioComp.current.play();
20+
};
21+
const pauseAudio = () => {
22+
setPlaying(false);
23+
audioComp.current.pause();
24+
};
25+
const incVolume = () => {
26+
if (audioComp.current.volume <= 0.9) {
27+
audioComp.current.volume += 0.1;
28+
}
29+
else {
30+
audioComp.current.volume = 1;
31+
}
32+
if (audioComp.current.muted) {
33+
audioComp.current.muted = false;
34+
setMuted(false);
35+
}
36+
};
37+
const decVolume = () => {
38+
audioComp.current.volume -= 0.1;
39+
if (audioComp.current.volume < 0.1) {
40+
audioComp.current.volume = 0;
41+
audioComp.current.muted = true;
42+
setMuted(true);
43+
}
44+
};
45+
const muteAudio = () => {
46+
audioComp.current.muted = !muted;
47+
setMuted(!muted);
48+
};
49+
return (
50+
<div className={styles.modernAudio}>
51+
{props.labelPosition === ModernAudioLabelPosition.TopLeft &&
52+
props.label !== "" &&
53+
<div><label>{props.label}</label></div>}
54+
{props.labelPosition === ModernAudioLabelPosition.TopCenter &&
55+
props.label !== "" &&
56+
<div style={{textAlign: "center"}}><label>{props.label}</label></div>}
57+
<div className={styles.audioPanel}>
58+
{props.audioUrl !== "" && <audio ref={audioComp} src={props.audioUrl}></audio>}
59+
<IconButton iconProps={{ iconName: 'Play' }} className={styles.audioIcon} title={strings.ModernAudioPlay} disabled={playing} onClick={playAudio} />
60+
<IconButton iconProps={{ iconName: 'Pause' }} className={styles.audioIcon} title={strings.ModernAudioPause} disabled={!playing} onClick={pauseAudio} />
61+
<IconButton iconProps={{ iconName: 'Volume2' }} className={styles.audioIcon} title={strings.ModernAudioIncVol} onClick={incVolume} />
62+
<IconButton iconProps={{ iconName: 'Volume0' }} className={styles.audioIcon} title={strings.ModernAudioDecVol} disabled={muted} onClick={decVolume} />
63+
<IconButton iconProps={{ iconName: 'VolumeDisabled' }} className={styles.audioIcon} title={strings.ModernAudioMute} disabled={muted} onClick={muteAudio} />
64+
</div>
65+
{props.labelPosition === ModernAudioLabelPosition.BottomLeft &&
66+
props.label !== "" &&
67+
<div><label>{props.label}</label></div>}
68+
{props.labelPosition === ModernAudioLabelPosition.BottomCenter &&
69+
props.label !== "" &&
70+
<div style={{textAlign: "center"}}><label>{props.label}</label></div>}
71+
</div>
72+
);
73+
};
74+
75+
ModernAudio.defaultProps = {
76+
label: "",
77+
labelPosition: ModernAudioLabelPosition.TopLeft
78+
};
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export enum ModernAudioLabelPosition {
2+
TopLeft = 1,
3+
TopCenter,
4+
BottomLeft,
5+
BottomCenter
6+
}

src/controls/modernAudio/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export * from './IModernAudioProps';
2+
export * from './ModernAudio';
3+
export * from './ModernAudioLabelPosition';

0 commit comments

Comments
 (0)