Skip to content
This repository has been archived by the owner on Apr 28, 2023. It is now read-only.

Commit

Permalink
refactor audio player knobs to args/controls
Browse files Browse the repository at this point in the history
  • Loading branch information
stephenhmarsh committed Jul 18, 2022
1 parent f067e57 commit a42dd5b
Show file tree
Hide file tree
Showing 7 changed files with 139 additions and 104 deletions.
17 changes: 11 additions & 6 deletions src/base/_colors.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,26 @@
//Colors
$color-met-red: #e4002b;
$color-red-error: #a6192e;
$color-green-good-news: #006540; // primary
$color-green-good-news-100: #004031;
$color-green-good-news-200: #006540;
$color-green-good-news-200: $color-green-good-news;
$color-green-good-news-300: #39a082; // this and above = not high enough contrast for white bg!
$color-green-good-news-400: #00ba84;
$color-green-good-news-500: #64f1c8;
$color-green-good-news-600: #e8fff7;
$color-green-good-news: $color-green-good-news-200;

$color-orange: #fe8800;
$color-pink-light: #ffe3f5;
$color-pink: #ce0058;
$color-purple: #5d1049;
$color-blue-light: #cfe4ff;

$color-purple: #5d1049; // primary
//Purplee is too cute of a typo to remove from the code.
$color-purplee: $color-purple;
$color-purple-100: #31009c;
$color-purple-200: #5700e8;
$color-purple-300: #7f38fb;
$color-purple-400: #bb86fc;
$color-purple-500: #d4b9f6;
$color-purple-600: #f2e7fe;
$color-blue-light: #cfe4ff;

//Greys
$color-black: #000006;
Expand Down Expand Up @@ -60,4 +64,5 @@ $color-text: $color-black;
$color-title: $color-black;
$color-background: $color-white;
$color-focus-state: $color-purple;
$color-focus-state-darkmode: $color-purple-400;
$color-focus-background: rgba($color-focus-state, 0.1);
2 changes: 1 addition & 1 deletion src/base/_sizes.scss
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ $line-length-max: 50em;

//Corner radii
$radius-sharp: 4px;
$radius-mild: 8px;
$radius-blunt: 8px;
$radius-soft: 16px;
$form-radius: $radius-sharp; // TODO: deprecate
$soft-radius: $radius-soft; // TODO: deprecate
Expand Down
61 changes: 27 additions & 34 deletions src/components/audio-player/audio-player-story-helpers.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { text } from "@storybook/addon-knobs";
import AudioPlayer from "./audio-player.js";
import greekHall1x1 from ".storybook/assets/images/greek-hall/1x1";

Expand Down Expand Up @@ -31,34 +30,6 @@ const initializeAudioPlayers = () => {
audioPlayers.forEach((player) => new AudioPlayer({wrapperEl: player}));
};

const defaultTrack = () => {
return {
id: 1,
audio: text("Audio File URL", "https://images.metmuseum.org/CRDImages/ad/audio/5TH-3865-ENG-134-1.mp3", "Track"),
image: { ...greekHall1x1,
w2400: greekHall1x1.srcSet.sizes["2440w"],
w1600: greekHall1x1.srcSet.sizes["1920w"],
w1200: greekHall1x1.srcSet.sizes["1240w"],
w840: greekHall1x1.srcSet.sizes["1240w"],
w560: greekHall1x1.srcSet.sizes["1240w"],
w280: greekHall1x1.srcSet.sizes["1240w"]
},
description: text("Description", "Praise Songs about Javascript", "Track"),
title: text("Title", "Track 1. Title", "Track"),
transcript: text(
"Transcript",
exampleTranscriptData,
"Track"
)
};
};

const track = (overrides={}) => {
return {
...defaultTrack(),
...overrides,
};
};

const exampleTranscriptData = `Figure, Abelam People
Sepik region, New Guinea (1981.415.1, 1978.412.871), Catalogue 27
Expand All @@ -79,11 +50,11 @@ NOTE: This was getting too long, so I made a few deletions.
LEVEL 2
(187 words)
NARRATOR: At the very top of this sculpture, you see two birds' heads. They have the distinctive long beaks of hornbills.* The large face below them is shown as though it were an Abelam man in full ceremonial dress.* And below the large face is carved a smaller figure, dressed similarly, with a rounded body and its arms raised.*
NARRATOR: At the very top of this sculpture, you see two birds&#39 heads. They have the distinctive long beaks of hornbills.* The large face below them is shown as though it were an Abelam man in full ceremonial dress.* And below the large face is carved a smaller figure, dressed similarly, with a rounded body and its arms raised.*
ERIC KJELLGREN: Now although these images are in human form, they actually depict spirits which live out in the forests and these spirits are known as nggwalndu. These spirits are particularly associated with yams.
And the yam species that they had among the Abelam was actually a gigantic species. They could grow up to about twelve feet long and as thick around as a human leg. In fact, yams could grow almost as large as the wooden image we're looking at here now.
And the yam species that they had among the Abelam was actually a gigantic species.They could grow up to about twelve feet long and as thick around as a human leg.In fact, yams could grow almost as large as the wooden image we&#39re looking at here now.
NARRATOR: Each prominent man had a ceremonial yam-exchange partner in a neighboring village. The men competed to see who could present the other with a larger yam. The exchange constituted a form of ritual warfare, dissipating social tension that might otherwise have erupted in the form of physical attack.
Expand All @@ -94,14 +65,36 @@ EXISTING STOP 1718 Figure, Kambot
Sepik Region, New Guinea (1978.412.823), Catalogue 52
246 words
NARRATOR-This impressive, life-size figure originally adorned a supporting post in a men's ceremonial house-among the Kambot people of New Guinea. Curator Eric Kjellgren:
NARRATOR - This impressive, life - size figure originally adorned a supporting post in a men&#39s ceremonial house-among the Kambot people of New Guinea. Curator Eric Kjellgren:
ERIC KJELLGREN--Although it represents a remote ancestor, this image is actually decorated much like a Kambot man would be when wearing essentially his best ritual finery. If you look around the neck of the image, you can see a series of crescents that go down the chest. These are almost certainly images of pearl shells.
NARRATOR: One of the most unusual aspects of this figure is that his face can be interpreted as several distinct images. The elongated form of the head can be seen as the head of a crocodile*, or as a stylized human face.* The raised sections on the outside of the face represent two long narrow eyes, meeting at a long nose, which stretches down to a small, red mouth at the base of the face.*
If you look at the very top of the forehead, you see a circle with a red center.* This represents the head of a second figure. The long, curved eyes appear as arms, descending down on either side to two hands, which form the nostrils of the larger face.* Clasped in the hands, the nose of the first image here likely represents a flute. Such flutes were secret objects, known only to initiated men. This subtle reference almost certainly indicates that the statue contains further hidden imagery understood only by the initiated.
NOTE: Eric: it would be great to include the Sepik flute recordings you mentioned. How could we get them?`;
NOTE: Eric: it would be great to include the Sepik flute recordings you mentioned.How could we get them ? `;

const track = {
id: 1,
audio: "https://images.metmuseum.org/CRDImages/ad/audio/5TH-3865-ENG-134-1.mp3",
image: {
...greekHall1x1,
w2400: greekHall1x1.srcSet.sizes["2440w"],
w1600: greekHall1x1.srcSet.sizes["1920w"],
w1200: greekHall1x1.srcSet.sizes["1240w"],
w840: greekHall1x1.srcSet.sizes["1240w"],
w560: greekHall1x1.srcSet.sizes["1240w"],
w280: greekHall1x1.srcSet.sizes["1240w"]
},
description: "Praise Songs about Javascript",
title: "Track 1. Title",
transcript: exampleTranscriptData,
};

const playlist = {
tracks: [track, { ...track, id: 2 }, { ...track, id: 3 }, { ...track, id: 4 }, { ...track, id: 5 }]
};


export { initializeAudioPlayers, track, example, exampleTranscriptData };
export { initializeAudioPlayers, track, playlist, example, exampleTranscriptData };
2 changes: 2 additions & 0 deletions src/components/audio-player/audio-player.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,12 +123,14 @@ class AudioPlayer {
}

this.wrapperEl.dispatchEvent(this.beforeTrackChange);

this.wrapperEl.querySelector(".is-active-track").classList.remove("is-active-track");
newTrackEl.classList.add("is-active-track");
let newTrack = JSON.parse(newTrackEl.dataset.track);
this.setTrack(newTrack);
this.setTranscript();
this.audioEl.play();

this.wrapperEl.dispatchEvent(this.afterTrackChange);
}

Expand Down
2 changes: 1 addition & 1 deletion src/components/audio-player/audio-player.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

.audio-player {
background-color: $color-white;
border-radius: $radius-mild;
border-radius: $radius-blunt;
box-shadow: $shadow-passive;
color: $color-black;
overflow: hidden;
Expand Down
157 changes: 95 additions & 62 deletions src/components/audio-player/audio-player.stories.js
Original file line number Diff line number Diff line change
@@ -1,50 +1,62 @@
import { html } from ".storybook/helpers";
import { useEffect } from "@storybook/client-api";
import { withKnobs, boolean, select } from "@storybook/addon-knobs";
import { playIcon, pauseIcon, rewindTenSecondsIcon, forwardTenSecondsIcon, upCaretIcon } from ".storybook/assets/svg";
import coverImageTemplate from "./cover-image-template";
import { initializeAudioPlayers, track, example } from "./audio-player-story-helpers";

export default { title: "Media/Audio Player", decorators: [withKnobs] };

const data = ({hasImage=true, numberOfTracks="single", darkMode=false, breathingRoom=false, playerMode=""}) => {

const options = {
hasImage: boolean("Has Image", hasImage, "Track"),
numberOfTracks: select("Single Track or Playlist?", {Single: "single", Playlist: "playlist"}, numberOfTracks, "Player"),
isDark: boolean("Dark mode?", darkMode, "Player") ? "inverted-colors" : "",
breathingRoom: boolean("Give it some breathing room?", breathingRoom, "Player") ? "padding: 40px; background-color: #eee" : "",
playerMode: select("Player Mode", {Default: "", "Mini Player": "mini-player", "Micro Player": "micro-player"}, playerMode, "Player")
};

let playlist = options.numberOfTracks == "playlist" ? { tracks: [
track({title: "Track 1"}),
track({...example}),
track({title: "Track 3", id: 3, transcript: null}),
track({title: "Track 4", id: 4, transcript: null}),
track({title: "Track 5", id: 4, transcript: null})
]} : null;

return {
options,
model: {
playlist: playlist,
track: track()
import { initializeAudioPlayers, track, playlist } from "./audio-player-story-helpers";

const argTypes = {
breathingRoom: {
name: "Give it some breathing room?"
},
darkMode: { name: "Dark Mode" },
hasImage: { name: "Has Image?" },
transcriptIsOpen: { name: "Force Transcript Area To Be Open?", },
playerMode: {
options: ["Regular", "Mini", "Micro"],
mapping: {
Regular: "",
Mini: "mini-player",
Micro: "micro-player"
},
type: "Select",
name: "Player Mode"
},
playlist: {
name: "Playlist Tracks",
options: ["1", "2", "3", "4", "5"],
defaultValue: [],
control: {
type: "check",
}
};
}
};

const audioPlayerMarkUp = ({model, options}) => html`
<div style="${options.breathingRoom}">
<section class="audio-player js-marble-audio-player ${options.playerMode} ${options.isDark}">
const args = {
breathingRoom: false,
darkMode: false,
hasImage: true,
transcriptIsOpen: false,
track,
};

export default { title: "Media/Audio Player", argTypes };

const wrapInTranscriptDiv = ({ transcriptIsOpen }, markup) => (
transcriptIsOpen ?
html`<div class="transcript-is-open">${markup}</div>` :
markup);

const audioPlayerMarkUp = (args) => wrapInTranscriptDiv(args, html`
<div ${args.breathingRoom ? "style=\"padding: 40px; background-color: #eee\"" : ""}">
<section class="audio-player js-marble-audio-player ${args.playerMode} ${args.darkMode ? " inverted-colors" : ""}">
<div class="audio-player__media-section">
<div class="audio-player__image-section">
<div class="audio-player__image-wrapper js-audio-player__image-wrapper">${options.hasImage ? coverImageTemplate(model.track.image) : "" }</div>
<div class="audio-player__image-wrapper js-audio-player__image-wrapper">${args.hasImage ? coverImageTemplate(args.track.image) : "" }</div>
</div>
<div class="audio-player__body">
<div class="audio-player__headings">
<h1 class="audio-player__title js-audio-player__title">${model.track.title}</h1>
<h2 class="audio-player__subtitle js-audio-player__subtitle">${model.track.description}</h2>
<h1 class="audio-player__title js-audio-player__title">${args.track.title}</h1>
<h2 class="audio-player__subtitle js-audio-player__subtitle">${args.track.description}</h2>
</div>
<div class="audio-player__controls-wrapper">
<div class="audio-controls">
Expand Down Expand Up @@ -88,16 +100,16 @@ const audioPlayerMarkUp = ({model, options}) => html`
<audio
class="js-audio-player__audio audio-player__audio-element"
data-track='${JSON.stringify(model.track)}'
title="${model.track.title}"
data-track='${JSON.stringify(args.track)}'
title="${args.track.title}"
style="width: 100%; height: 36px;"
controls
>
<source src="${model.track.audio}" />
<source src="${args.track.audio}" />
<!-- TODO: playlist links, too!! -->
<p>
Your browser doesn't support HTML5 audio. Here is a
<a href="${model.track.audio}"
<a href="${args.track.audio}"
>link to download the audio</a
>
instead.
Expand All @@ -109,10 +121,10 @@ const audioPlayerMarkUp = ({model, options}) => html`
</div>
<div
class="audio-player__transcript-section audio-player__transcript-section--transcript-${!!model?.track?.transcript?.length} js-audio-player__transcript-section">
class="audio-player__transcript-section audio-player__transcript-section--transcript-${!!args?.track?.transcript?.length} js-audio-player__transcript-section">
<div class="audio-player__transcript-wrapper js-audio-player__transcript-wrapper">
<div class="audio-player__transcript js-audio-player__transcript" tabindex=0>
${model.track.transcript}
${args.track.transcript}
</div>
</div>
<a class="audio-player__transcript-toggle js-audio-player__transcript-toggle" href="#">
Expand All @@ -121,9 +133,11 @@ const audioPlayerMarkUp = ({model, options}) => html`
</a>
</div>
<ol class="js-audio-player__playlist-container audio-player__playlist">${ model.playlist?.tracks?.length ? html`
<ol class="js-audio-player__playlist-container audio-player__playlist">${ args.playlist?.length ? html`
<h4 class="audio-player__playlist-title">Playlist</h4>
${model.playlist.tracks.map(playlistTrack => { return html`
${args.playlist.map(playlistTrackIndex => {
const playlistTrack = playlist.tracks[playlistTrackIndex - 1];
return html`
<li class="js-audio-player__playlist-track audio-player__playlist-track" data-track='${JSON.stringify(playlistTrack)}'>
<img
class="audio-player__playlist-track-thumbnail"
Expand All @@ -136,46 +150,65 @@ const audioPlayerMarkUp = ({model, options}) => html`
</section>
</div>
`;
`);

const FullPlayer = () => {
const Player = (args) => {
useEffect(initializeAudioPlayers);
return audioPlayerMarkUp(data({}));
return audioPlayerMarkUp(args);
};

const MultiplePlayers = () => {
const FullPlayer = (args) => Player(args);
FullPlayer.args = args;

const MultiplePlayers = (args) => {
useEffect(initializeAudioPlayers);
return html`
<div>
${audioPlayerMarkUp(data({}))}
${audioPlayerMarkUp(data({}))}
${audioPlayerMarkUp(args)}
${audioPlayerMarkUp(args)}
</div>`;
};
MultiplePlayers.args = args;

const FullPlayerWithOpenTranscript = () => {
useEffect(initializeAudioPlayers);
return html`<div class="transcript-is-open">${audioPlayerMarkUp(data({}))}</div>`;
const FullPlayerWithOpenTranscript = (args) => Player(args);
FullPlayerWithOpenTranscript.args = {
...args,
transcriptIsOpen: true
};

const FullPlayerWithPlaylist = () => {
useEffect(initializeAudioPlayers);
return audioPlayerMarkUp(data({numberOfTracks: "playlist"}));
const FullPlayerWithPlaylist = (args) => Player(args);
FullPlayerWithPlaylist.args = {
...args,
playlist: ["1", "2", "3", "4", "5"]
};

const MiniPlayer = () => {
useEffect(initializeAudioPlayers);
return audioPlayerMarkUp(data({playerMode: "mini-player"}));
const MiniPlayer = (args) => Player(args);
MiniPlayer.args = {
...args,
playerMode: "mini-player"
};

const MicroPlayer = () => {
useEffect(initializeAudioPlayers);
return audioPlayerMarkUp(data({playerMode: "micro-player"}));
const MicroPlayer = (args) => Player(args);
MicroPlayer.args = {
...args,
playerMode: "micro-player"
};

const FullPlayerDarkModeKitchenSink = (args) => Player(args);
FullPlayerDarkModeKitchenSink.args = {
...args,
darkMode: true,
hasImage: true,
playlist: ["1", "2", "3", "4", "5"],
transcriptIsOpen: true,
};

export {
FullPlayer,
FullPlayerWithOpenTranscript,
FullPlayerWithPlaylist,
FullPlayerDarkModeKitchenSink,
MiniPlayer,
MicroPlayer,
MultiplePlayers
MultiplePlayers,
};
Loading

0 comments on commit a42dd5b

Please sign in to comment.