diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 94b5dbf..a3d097e 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,45 +1,27 @@
# Contribute
-This started out as a "scratch your own itch" tool for a specific project. I'm open-sourcing it in the hope it might prove useful to others too. There are _a few_ audio player tools/plugins out there, but most have too many features for my needs. I like simplicity, and I like any JS I add to my sites to be as lean as possible.
+Picobel started out in 2015 as a "scratch your own itch" tool for a specific project which I then open-sourced in the hope it might prove useful to others.
-I'm hoping Picobel can be of use to as many people as possible. If you have an improvement or bug-fix or new feature, get in touch! Make a pull request on the [Picobel.js Github repo](https://github.com/tomhazledine/picobel). I'm just getting started with "open source", so I'd be very glad of any help or suggestions or advice.
+If you have an improvement or bug-fix or new feature, get in touch! Make a pull request on the [Picobel.js Github repo](https://github.com/tomhazledine/picobel). Contributions are encouraged and any feedback (positive or negative) is very welcome.
-## Dev dependencies
+## Making changes
-Once you've forked the repo, run `npm install` to install the development dependencies. I'm trying to keep the build chain as short as possible, so there's not too much to be installed:
+To make changes to Picobel, you'll need to follow these steps:
-* `babel-cli` and `babel-preset-env` are there to transpile the raw ES6 from [`/esm/picobel.js`](https://github.com/tomhazledine/picobel/blob/master/esm/picobel.js) into the ES5-compatible versions.
-* `node-sass` is there to compile the SCSS in [`/scss/`](https://github.com/tomhazledine/picobel/blob/master/scss) into vanilla CSS.
-* Once the regular SCSS has been compiled, it gets run through `autoprefixer` (using `postcss-cli`) to make sure the necessary browser prefixes are added to the raw CSS.
-* To compile the ES6/UMD modules, I've added `webpack` (and `webpack-cli` and `babel-loader`).
-* The test suite is run using `jest`.
+1. fork the repo and clone it to your local machine.
+2. install the dev dependencies with `yarn` (or `npm install`).
+3. make changes to the code in the `/src` directory.
+4. run `yarn build` (or `npm run build`) to compile the code. There is also `yarn build:dev` (or `npm run build:dev`) which will watch for changes and recompile automatically as well as generating source maps for the compiled files. Once built, the final code will appear in the `/build` directory.
+5. run `yarn test` (or `npm run test`) to run the test suite.
+6. commit your changes and make a pull request.
-## Editing the JS
+## Project structure
-The canonical source code lives with the [`/src`](https://github.com/tomhazledine/picobel/blob/master/src) directory. This is where you should make any changes to the JavaScript code.
+### JavaScript
-Wherever possible I've tried to keep all functions as ["pure"](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-pure-function-d1c076bec976) as possible: given the same arguments, they should always return the same result, without any side effects. I'm a recent convert to the world of "functional" programming, so accept that I might not always get it right - if you can suggest any improvements, I'll be more than happy to hear them 👍.
+Picobel is first-and-foremost a JavaScript project, and all the JS code lives in [`/src/js`](https://github.com/tomhazledine/picobel/blob/master/src/js) with the main file being [`/src/js/Picobel.js`](https://github.com/tomhazledine/picobel/blob/master/src/js/Picobel.js). The function `picobel()` is the default export from this file, and is the function that gets called when you use Picobel in your own code.
-### Modules
-
-The code is written using ES6 (UMD) module syntax (e.g. `import VARIABLE from 'PACKAGE_NAME';`).
-
-As far as code organization goes, I've batched functions into roughly-similar groups, and put those groups into their own modules. The groups take the form of objects, that can then be imported into the main app. For example:
-
- // Module file:
- const groupedFunctions = {
- aCoolFunction: () => {/* the function code */},
- somethingUsefull: () => {/* the function code */}
- };
- export default groupedFunctions;
-
- // App file:
- import groupedFunctions from './path-to-module-file';
- function TheMainAPP() {
- // Use one of the grouped functions:
- groupedFunctions.aCoolFunction();
- }
- export default TheMainAPP;
+JS is written using ESM module syntax (e.g. `import { foo } from './bar.js';`), and helper-functions and utilities are imported from partials that also live in `/src/js`.
There are several modules in this project:
@@ -49,16 +31,22 @@ There are several modules in this project:
* `PicobelMarkup.js`: these functions handle creating the markup that Picobel replaces native `` elements with.
* `PicobelSetup.js`: these functions initialize Picobel (parsing options, generating initial `state`, etc.).
-Once you've finished making changes, run `npm run build` to generate the UMD and CommonJS versions (which will appear in `/esm/picobel.js` and `/cjs/picobel.js` respectively).
+The JS is compiled into a production-ready build using [esbuild](https://esbuild.github.io/), which is setup and configured in [`/build.js`](https://github.com/tomhazledine/picobel/blob/master/build.js) and run with `yarn build` (or `npm run build`).
-### Tests
+### CSS
-There are tests for most Picobel functions. Picobel uses Jest for running tests. Test files live in the `/tests` directory, and match the main module files: for example, the `/src/helpers.js` file has a corresponding test file called `/tests/helpers.tests.js`
+Picobel supports several pre-build "themes". A Picobel theme is a set of namespaced CSS rules that apply specific styles based on the theme name. For example, the default theme is called `default` and all the CSS rules for this theme are namespaced with `.picobel.default`.
-## Editing the CSS
+The themes are all written in vanilla CSS and can be found in [`/src/css`](https://github.com/tomhazledine/picobel/blob/master/src/css). Running the build step (with `yarn build` etc.) will create minified versions of the themes in the `/build` directory.
-The CSS themes are written in [SCSS](https://sass-lang.com/guide) and compiled to vanilla CSS using the `npm run styles` command. `npm run styles` compiles the SCSS and then runs it through [Autoprefixer](https://github.com/postcss/autoprefixer) to add all the required vendor prefixes.
+There are several stylesheets available:
-New themes should be named with the following pattern: `/scss/player.NEW_THEME_NAME.scss`. They must also be included in the "all themes" stylesheet: [`/scss/all.scss`](https://github.com/tomhazledine/picobel/blob/master/scss/all.scss)
+* `picobel.all.css`: a single stylesheet that contains all the themes. (useful for experimentation, but not recommended for production).
+* `picobel.default.css`: the default theme.
+* `picobel.skeleton.css`: a "bare bones" theme with minimal styling intended as a jumping-off point for folks to write their own themes. Includes basic layout, loading state, custom-styled volume and progress range sliders, etc.
- @import "player.NEW_THEME_NAME";
+* `picobel.bbc.css`: a theme that resembles the BBC iPlayer interface circa 2015.
+* `picobel.eatenbymonsters.css`: the theme built for [eatenbymonsters.com](https://eatenbymonsters.com) that was the initial inspiration for Picobel.
+* `picobel.itunes.css`: a theme that resembles the iTunes app mini-player interface circa 2015.
+* `picobel.pitchfork.css`: a theme that resembles the [Pitchfork](https://pitchfork.com/) web audio player interface circa 2015.
+* `picobel.soundcloud.css`: a theme that resembles the Soundcloud embedded web audio player interface circa 2015.
\ No newline at end of file
diff --git a/README.md b/README.md
index fea1b4f..484f5c1 100644
--- a/README.md
+++ b/README.md
@@ -2,16 +2,16 @@
Picobel.js
-[![Node.js CI](https://github.com/tomhazledine/picobel/actions/workflows/node.js.yml/badge.svg)](https://github.com/tomhazledine/picobel/actions/workflows/node.js.yml)
+v3.0.0
+
+
Picobel.js (pronounced _peek-o-bell_, as in _decibel_) is a lightweight dependency-free Javascript tool that converts html audio tags into styleable markup.
* [Overview](#why-would-i-need-this)
-* [Installation](#installation)
-* [Usage](#usage)
+* [Quick start](#quick-start)
* [Setting "artist" and "track name" values](#setting-artist-and-track-name-values)
* [Pre-made themes](#pre-made-themes)
-* [Contribute](#contribute)
## Why would I need this?
@@ -35,144 +35,63 @@ _Picobel-styled audio players_
**Picobel** allows you to create custom styles for your audio players: providing cross-browser consistency and a seamless integration with your existing brand styles.
-## Installation
-
-### Install with NPM
+## Quick start
-`npm install picobel` (or `yarn add picobel`) will install Picobel in your `node_modules` directory. Then you can include Picobel in your javascript like this:
-
-```js
-// Include Picobel in your project:
-import picobel from 'picobel';
+Add Picobel to your project:
-// Initialise picobel:
-picobel()
-
-// ...or initialise picobel with your chosen options:
-picobel({ theme: 'default' })
+```bash
+yarn add picobel
```
-If you are using WebPack (or similar) to bundle your scripts, you can include the stylesheet for your chosen Picobel theme here too:
+In your JS, initialise Picobel with your chosen class name:
```js
-// Include the styles for *all* the themes:
-import 'picobel/css/all.css';
+import picobel from "picobel";
-// ...or include only the styles for a specific theme:
-import 'picobel/css/player.default.css';
+picobel({theme: "my-awesome-audio-player"});
```
-Alternatively you could include the stylesheets manually with a ` ` tag in your `index.html`:
+Picobel will then find any `` elements on the page and replace them with markup you can style with CSS.
-```html
-
-
-```
-
-When your page loads, Picobel will replace any default `` elements with a block of custom-markup, complete with classes that you can use to apply your custom CSS.
-
-### Manually install
-
-To use **Picobel.js** you'll need to include the `picobel.js` file (found here: [picobel.legacy.min.js](https://github.com/tomhazledine/picobel/blob/master/picobel.legacy.min.js)) in your project. This needs to be called before your custom scripts, and ideally in the `` of your page.
-
-```html
-
-
-```
-
-You will also need the CSS styles. Choose which "theme" you'd like to use, and load that stylesheet. All current themes can be previewed in the [Picobel.js CodePen Collection](http://codepen.io/collection/XpZEor/), and all the css files can be found in the repo, [here](https://github.com/tomhazledine/picobel/tree/master/css).
-
-```html
-
-
-```
+## Setting "artist" and "track name" values
-Then initialize the function. For simplicity, the example below does this in an in-line `
+
+ Your browser does not support the audio
element.
+
```
-When your page loads, Picobel will replace any default `` elements with a block of custom-markup, complete with classes that you can use to apply your custom CSS.
-
-## Usage
+## Using premade themes
-If you're using a theme other than "basic", you'll need to specify the theme name in the options object when you intialise Picobel.
+Picobel comes with several pre-made themes that you can use out-of-the-box. To use a theme, simply pass the theme name to the `picobel()` function:
```js
-Picobel( { theme: 'themename' } );
+picobel({theme: "default"});
```
-This adds a class to the container of each audio element, so if you've made your own styles you can use this to make sure your CSS is nicely namespaced.
-
-### This:
-
-```html
-
-```
-
-### Gets turned into this:
-
-```html
-
-
-
- play
-
-
- file.mp3
-
-
-
-
-
-```
-
-## Setting "artist" and "track name" values
-
-Applying metadata to your audio file requires adding data-attributes to your `` markup. Picobel gets the track name from the regular `title` attribute, and looks for artist information in the `data-artist` attribute. For the demo at the top of this page, the markup looks like this:
+Then include the theme's CSS in your project:
```html
-
- Your browser does not support the audio
element.
-
+
```
## Pre-made themes
-Picobel comes with many pre-made themes. To use a theme, make sure you've downloaded the correct stylesheet from the [Picobel CSS library](https://github.com/tomhazledine/picobel/tree/master/css) and then reference the chosen theme name as an option when you initialize Picobel in your JS.
+Picobel comes with a few pre-made themes (for times when you don't want to style an entire audio player from scratch). To use a theme, make sure you've downloaded the correct stylesheet from the [Picobel CSS library](https://github.com/tomhazledine/picobel/tree/master/src/css) and then reference the chosen theme name as an option when you initialize Picobel in your JS.
```html
-
+
+
+
+
```
-So if you wanted to use the "iTunes" theme, your Picobel call would look like this: `Picobel({theme:"itunes"});`. If you don't explicitly choose a theme, then the Default theme will be used. The current options are: `skeleton`, `itunes`, `bbc`, `soundcloud`, `pitchfork`, & `eatenbymonsters`.
+So if you wanted to use the "iTunes" theme, your Picobel call would look like this: `Picobel({theme:"itunes"});`. If you don't explicitly choose a theme, then the Default theme will be used. The current options supported by Picobel v3 are: `skeleton` & `default`.
You can see them all in action in the [Picobel.js CodePen Collection](http://codepen.io/collection/XpZEor/), and see screenshots of each featured theme on this page:
@@ -182,25 +101,4 @@ _Default theme. [View the this theme on CodePen](http://codepen.io/tomhazledine/
![Skeleton theme](images/theme_skeleton.png)
_Skeleton theme (use this as a jumping-off point for your own styles). [View the this theme on CodePen](http://codepen.io/tomhazledine/pen/zZXyGa)_
-![BBC iPlayer theme](images/theme_bbc.png)
-_BBC iPlayer-esque theme. [View the this theme on CodePen](http://codepen.io/tomhazledine/pen/kXZaKL)_
-
-![iTunes theme](images/theme_itunes.png)
-_iTunes-esque theme. [View the this theme on CodePen](http://codepen.io/tomhazledine/pen/NAyWQW)_
-
-![Soundcloud theme](images/theme_soundcloud.png)
-_Soundcloud-esque theme. [View the this theme on CodePen](http://codepen.io/tomhazledine/pen/VpNqjJ)_
-
-![Pitchfork theme](images/theme_pitchfork.png)
-_Pitchfork-esque theme. [View the this theme on CodePen](http://codepen.io/tomhazledine/pen/OpGrXN)_
-
-![Eaten by Monsters theme](images/theme_ebm.png)
-_Eaten by Monsters theme. [View the this theme on CodePen](http://codepen.io/tomhazledine/pen/gmyZLP)_
-
-## Contribute
-
-This started out as a "scratch your own itch" tool for a specific project. I'm open-sourcing it in the hope it might prove useful to others too. There are _a few_ audio player tools/plugins out there, but most have too many features for my needs. I like simplicity, and I like any JS I add to my sites to be as lean as possible.
-
-I'm hoping Picobel can be of use to as many people as possible. If you have an improvement or bug-fix or new feature, get in touch! Make a pull request on the [Picobel.js Github repo](https://github.com/tomhazledine/picobel). I'm just getting started with "open source", so I'd be very glad of any help or suggestions or advice.
-
-Read more about contribute in this project's [Contribution Guide](https://github.com/tomhazledine/picobel/blob/master/CONTRIBUTING.md)
\ No newline at end of file
+**Note:** several other themes were available with <=v2 of Picobel, but have been removed in v3. If you need access to these themes, you can still use Picobel v2.1.0. They will return to v3 soon along with a detailed migration guide for upgrading to v3.
\ No newline at end of file
diff --git a/build.js b/build.js
index 93eb620..1bc17d5 100644
--- a/build.js
+++ b/build.js
@@ -1,14 +1,7 @@
import * as esbuild from "esbuild";
+import { parseArgs, getPackageVersion, watchFiles } from "./build.utils.js";
-const parseArgs = rawArgs => {
- const [a, b, ...relevant] = rawArgs;
- return relevant
- .map(arg => {
- const [key, value] = arg.split("=");
- return { [key.replace(/-/g, "")]: value || true };
- })
- .reduce((args, arg) => ({ ...args, ...arg }), {});
-};
+const version = getPackageVersion();
const args = parseArgs(process.argv);
@@ -24,20 +17,27 @@ const config = {
js: {
...globalConfig,
format: "esm",
- entryPoints: ["src/js/Picobel.js"],
+ entryPoints: ["src/js/index.js"],
entryNames: "picobel"
},
+ legacy: {
+ ...globalConfig,
+ entryPoints: ["src/js/legacy.js"],
+ entryNames: `picobel.${version}`,
+ format: "iife"
+ },
css: {
...globalConfig,
entryPoints: [
- "src/css/all.css",
- "src/css/player.default.css",
- "src/css/player.skeleton.css",
- "src/css/player.bbc.css",
- "src/css/player.eatenbymonsters.css",
- "src/css/player.itunes.css",
- "src/css/player.pitchfork.css",
- "src/css/player.soundcloud.css"
+ "src/css/picobel.all.css",
+ "src/css/picobel.main.css",
+ "src/css/picobel.default.css",
+ "src/css/picobel.skeleton.css",
+ "src/css/picobel.bbc.css",
+ "src/css/picobel.eatenbymonsters.css",
+ "src/css/picobel.itunes.css",
+ "src/css/picobel.pitchfork.css",
+ "src/css/picobel.soundcloud.css"
]
}
};
@@ -46,9 +46,24 @@ const build = async config => {
try {
await esbuild.build(config.js);
await esbuild.build(config.css);
+ await esbuild.build(config.legacy);
} catch (e) {
+ if (e.errors && e.errors[0].location) {
+ console.log({ location: e.errors[0].location });
+ }
console.warn("esbuild error", e);
}
};
-build(config);
+if (args.mode === "development") {
+ // Development mode
+ watchFiles(["src/js", "src/css"], async file => {
+ console.log(`Changes detected in ${file}.\nRebuilding...`);
+ await build(config);
+ console.log("Build complete.");
+ });
+} else {
+ // Production mode
+ await build(config);
+ console.log("Build complete.");
+}
diff --git a/build.utils.js b/build.utils.js
new file mode 100644
index 0000000..fb60b24
--- /dev/null
+++ b/build.utils.js
@@ -0,0 +1,38 @@
+import readline from "readline";
+import fs from "fs";
+
+export const parseArgs = rawArgs => {
+ const [a, b, ...relevant] = rawArgs;
+ return relevant
+ .map(arg => {
+ const [key, value] = arg.split("=");
+ return { [key.replace(/-/g, "")]: value || true };
+ })
+ .reduce((args, arg) => ({ ...args, ...arg }), {});
+};
+
+export const watchFiles = (files, onChange) => {
+ console.log(`Press "q" to exit`);
+ readline.emitKeypressEvents(process.stdin);
+ process.stdin.setRawMode(true);
+
+ process.stdin.on("keypress", async (str, key) => {
+ if (key.name === "q") {
+ console.log("stopped watching");
+ process.exit();
+ }
+ });
+ files.forEach(file => {
+ fs.watch(file, (eventType, filename) => {
+ if (filename) {
+ onChange(filename);
+ }
+ });
+ });
+};
+
+export const getPackageVersion = () => {
+ const packageJson = fs.readFileSync("./package.json");
+ const { version } = JSON.parse(packageJson);
+ return version;
+};
diff --git a/demo/audio-examples/taken-at-the-flood.mp3 b/demo/audio-examples/taken-at-the-flood.mp3
new file mode 100644
index 0000000..9078c95
Binary files /dev/null and b/demo/audio-examples/taken-at-the-flood.mp3 differ
diff --git a/demo/audio-examples/taken-at-the-flood.ogg b/demo/audio-examples/taken-at-the-flood.ogg
new file mode 100644
index 0000000..ae869ba
Binary files /dev/null and b/demo/audio-examples/taken-at-the-flood.ogg differ
diff --git a/demo/build.js b/demo/build.js
index eb21941..696f53e 100644
--- a/demo/build.js
+++ b/demo/build.js
@@ -1,14 +1,5 @@
import * as esbuild from "esbuild";
-
-const parseArgs = rawArgs => {
- const [a, b, ...relevant] = rawArgs;
- return relevant
- .map(arg => {
- const [key, value] = arg.split("=");
- return { [key.replace(/-/g, "")]: value || true };
- })
- .reduce((args, arg) => ({ ...args, ...arg }), {});
-};
+import { parseArgs, watchFiles } from "../build.utils.js";
const args = parseArgs(process.argv);
@@ -18,8 +9,8 @@ const config = {
minify: args.mode !== "development",
treeShaking: args.mode !== "development",
sourcemap: args.mode === "development",
- entryPoints: ["demo/index.js"],
- entryNames: "picobel-demo"
+ entryPoints: ["demo/index.js", "demo/composable.js", "demo/types.js"],
+ entryNames: "picobel-demo-[name]"
};
const build = async config => {
@@ -31,4 +22,14 @@ const build = async config => {
}
};
-build(config);
+if (args.mode === "development") {
+ // Development mode
+ watchFiles(["build", "demo/index.js"], async file => {
+ console.log(`Changes detected in ${file}.\nRebuilding...`);
+ await build(config);
+ });
+} else {
+ // Production mode
+ await build(config);
+ console.log("Build complete.");
+}
diff --git a/demo/composable.html b/demo/composable.html
new file mode 100644
index 0000000..b5ee55b
--- /dev/null
+++ b/demo/composable.html
@@ -0,0 +1,79 @@
+
+
+
+
+ Picobel.js Test Page
+
+
+
+
+
+
+
+
+
+
Testing Picobel: composable components
+
+
Just play and progress
+
+ Your browser does not support the
+ audio
element.
+
+
+
+
Some stuff...
+
...inbetween the audio elements
+
+
+
+ Your browser does not support the
+ audio
element.
+
+
+
+
+
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dicta
+ recusandae deleniti ut, sit in aliquam vel repellat nulla id
+ temporibus iure pariatur doloribus, magnam voluptatibus? Inventore
+ natus earum nisi ducimus.
+
+
+
+
+ Your browser does not support the audio
element.
+
+
+
+
+
+
+
diff --git a/demo/composable.js b/demo/composable.js
new file mode 100644
index 0000000..2b55deb
--- /dev/null
+++ b/demo/composable.js
@@ -0,0 +1,22 @@
+import picobel from "../build/picobel.js";
+
+const section01 = document.querySelector("#section-01");
+const section02 = document.querySelector("#section-02");
+const section03 = document.querySelector("#section-03");
+
+const instance01 = picobel({
+ theme: "bare",
+ components: ["playPause", "progress"],
+ context: section01
+});
+
+const instance02 = picobel({
+ theme: "bare",
+ // components: ["playPause", "progress"],
+ context: section02
+});
+const instance03 = picobel({
+ theme: "bare",
+ components: ["playPause", ["progress", ["duration", "timer"]]],
+ context: section03
+});
diff --git a/demo/index.html b/demo/index.html
index 3a1a2a4..4a15982 100644
--- a/demo/index.html
+++ b/demo/index.html
@@ -5,29 +5,48 @@
Picobel.js Test Page
-
+
+
+
+
+
+
Testing Picobel: home
Your browser does not support the audio
element.
+
noop
+
+
Some stuff...
...inbetween the audio elements
+
Your browser does not support the audio
element.
@@ -40,7 +59,7 @@ Some stuff...
@@ -48,6 +67,9 @@ Some stuff...
-
+