diff --git a/.github/workflows/podman-image.yml b/.github/workflows/podman-image.yml index 3118fc87..dc1602a3 100644 --- a/.github/workflows/podman-image.yml +++ b/.github/workflows/podman-image.yml @@ -43,7 +43,7 @@ jobs: ${{ runner.os }}-18-pnpm-store- - run: pnpm i --frozen-lockfile - - run: pnpm run build + - run: VITE_DOCS=true pnpm run build:all - run: pnpm run test # Unchanged from the original. diff --git a/.npmrc b/.npmrc new file mode 100644 index 00000000..66a265e7 --- /dev/null +++ b/.npmrc @@ -0,0 +1,2 @@ +public-hoist-pattern[]=@babel/* +public-hoist-pattern[]=@mdx-js/* diff --git a/README.md b/README.md index 427c776f..35281f93 100644 --- a/README.md +++ b/README.md @@ -2,4 +2,54 @@ Timeliner is a reimplementation of [Variations Audio Timeliner](http://variations.sourceforge.net/vat/index.html) as a web application, using the [IIIF Presentation API 3.0](https://iiif.io/api/presentation/3.0/). -[Documentation](https://iiif-timeliner.netlify.com/docs) | [User stories](https://github.com/digirati-co-uk/timeliner/issues?q=is%3Aissue+is%3Aopen+label%3A"%3Abusts_in_silhouette%3A+user+story") ([Kanban](https://github.com/digirati-co-uk/timeliner)) | [UX Wireframe](https://preview.uxpin.com/874bd44d74fc6062565cd95dc2dfc9e694b6ed4f#/pages/92279172/simulate/no-panels?mode=i) | [Original timeliner](http://variations.indiana.edu/use/timelines.html) | [Demo site](https://iiif-timeliner.netlify.com) | [Changelog](https://github.com/digirati-co-uk/timeliner/issues?q=is%3Aissue+is%3Aclosed+milestone%3A"UI+Components+1.0") +## Installation + +Node 18+ and `yarn` are required. + +``` +yarn install +``` + +## Development + +Start the main application at at [http://localhost:5173/](http://localhost:5173/) with hot-reload using, + +``` +yarn start +``` + +Start the documentation site in development mode at [http://localhost:3000/](http://localhost:3000/) using, + +``` +yarn docz:dev +``` + +## Building + +Build the main application, + +``` +yarn build +``` + +Build the main application and documentation together, + +``` +yarn build:all +``` + +Preview the production build (main app + docs) at [http://localhost:5173/](http://localhost:5173/) and docs at [http://localhost:5173/docs](http://localhost:5173/docs) using, + +``` +yarn preview +``` + +## Testing + +``` +yarn test +``` + +## Links + +[Documentation](https://timeliner.dlib.indiana.edu/docs) | [User stories](https://github.com/digirati-co-uk/timeliner/issues?q=is%3Aissue+is%3Aopen+label%3A"%3Abusts_in_silhouette%3A+user+story") | [UX Wireframe](https://preview.uxpin.com/874bd44d74fc6062565cd95dc2dfc9e694b6ed4f#/pages/92279172/simulate/no-panels?mode=i) | [Original timeliner](http://variations.indiana.edu/use/timelines.html) | [Demo site](https://timeliner.dlib.indiana.edu/) | [Changelog](https://github.com/digirati-co-uk/timeliner/issues?q=is%3Aissue+is%3Aclosed+milestone%3A"UI+Components+1.0") diff --git a/doczrc.js b/doczrc.js new file mode 100644 index 00000000..0b8481de --- /dev/null +++ b/doczrc.js @@ -0,0 +1,65 @@ +const path = require('path'); +const webpack = require('webpack'); + +export default { + title: 'Timeliner', + repository: "https://github.com/IUBLibTech/timeliner", + description: 'IIIF Timeliner Documentation', + base: process.env.DOCZ_BASE || '/docs', + dest: './dist/docs', + src: './src', + wrapper: 'src/components/docs/components/DocsWrapper/DocsWrapper', + files: '**/*.{md,markdown,mdx}', + menu: [ + 'Getting started', + 'User stories', + 'Technical Documentation', + ], + onCreateWebpackChain(config) { + // Force all imports of 'docz' to resolve to the same copy so that the + // shared React context is a single instance. + config.resolve.alias.set( + 'docz', + path.resolve(__dirname, 'node_modules/docz') + ); + // Add SCSS support + config.module + .rule('scss') + .test(/\.scss$/) + .use('style-loader') + .loader('style-loader') + .end() + .use('css-loader') + .loader('css-loader') + .options({ sourceMap: false }) + .end() + .use('sass-loader') + .loader('sass-loader') + .options({ + implementation: require('sass'), + sourceMap: false, + }) + .end(); + + // Plain CSS files (e.g. from third-party imports) + config.module + .rule('css') + .test(/\.css$/) + .use('style-loader') + .loader('style-loader') + .end() + .use('css-loader') + .loader('css-loader') + .options({ sourceMap: false }) + .end(); + + // Expose VITE_DOCS to the docz/webpack bundle for conditional rendering in DocsWrapper + config + .plugin('define') + .use(webpack.DefinePlugin, [{ + 'process.env.VITE_DOCS': JSON.stringify(process.env.VITE_DOCS) + }]); + + return config; + }, +}; diff --git a/index.html b/index.html index e21d13ba..d49c1966 100644 --- a/index.html +++ b/index.html @@ -1,46 +1,46 @@ - - - - - - - Timeliner - - - -
-

IIIF Timeliner

-
-

- Timeliner is a reimplementation of Variations Audio Timeliner as a web - application, using the IIIF Presentation API 3.0. As with the original - version, developed as a part of the Variations Digital Music Library - System, it is an audio annotation and analysis tool for creating and - labeling bubble diagrams. These diagrams can be used to navigate music - or other audio for detailed study. -

-

- In addition to its use as a standalone application, the Timeliner is - available as integrated feature within the successor to Variations, - Avalon Media System. Avalon users can create new bubble diagrams - directly from item pages within their Avalon instance and edit, share - and copy timelines across all items in the repository. -

-

- Please note that due to standard browser security, audio resources - used with Timeliner must be set up for Cross-origin resource sharing - (CORS). This is not necessarily the case for many resources on the - web, and not all URLs for media files may work. -

-
+ + + + + + + + Timeliner + + + + +
+

IIIF Timeliner

+
+

+ Timeliner is a reimplementation of Variations Audio Timeliner as a web + application, using the IIIF Presentation API 3.0. As with the original + version, developed as a part of the Variations Digital Music Library + System, it is an audio annotation and analysis tool for creating and + labeling bubble diagrams. These diagrams can be used to navigate music + or other audio for detailed study. +

+

+ In addition to its use as a standalone application, the Timeliner is + available as integrated feature within the successor to Variations, + Avalon Media System. Avalon users can create new bubble diagrams + directly from item pages within their Avalon instance and edit, share + and copy timelines across all items in the repository. +

+

+ Please note that due to standard browser security, audio resources + used with Timeliner must be set up for Cross-origin resource sharing + (CORS). This is not necessarily the case for many resources on the + web, and not all URLs for media files may work. +

+
+ - +
+ + diff --git a/netlify.toml b/netlify.toml deleted file mode 100644 index 64b953f8..00000000 --- a/netlify.toml +++ /dev/null @@ -1,12 +0,0 @@ -[Settings] - ID = "6631c5c5-fe72-4bd4-b668-36be86462b91" - -[Build] - Publish = "dist" - Functions = "" - -[[redirects]] - from = "docs/*" - to = "docs/index.html" - status = 200 - force = false \ No newline at end of file diff --git a/package.json b/package.json index f29698c9..c5ef1b23 100644 --- a/package.json +++ b/package.json @@ -9,10 +9,13 @@ "start": "vite", "build": "vite build", "test": "vitest --coverage", - "docz:dev": "docz dev", + "docz:dev": "DOCZ_BASE=/ docz dev", "docz:build": "docz build", + "build:all": "yarn build && yarn docz:build", + "preview": "VITE_DOCS=true yarn build:all && npx serve dist -p 5173", "watch": "vite build --watch", "snyk-protect": "snyk-protect", + "postinstall": "node scripts/patch-docz.js", "prepublish": "npm run snyk-protect" }, "devDependencies": { @@ -20,9 +23,14 @@ "@snyk/protect": "^1.1044", "@vitejs/plugin-react": "^4.3.1", "@vitest/coverage-v8": "^2.0.5", + "css-loader": "^4.3.0", + "docz": "1.2.0", "js-yaml": "4.1.1", "redux-saga-test-plan": "^3.7.0", + "sass": "^1.32.0", "sass-embedded": "^1.77.8", + "sass-loader": "^10.2.0", + "style-loader": "^2.0.0", "vite": "^5.4.21", "vitest": "^2.0.5" }, @@ -30,6 +38,7 @@ "@material-ui/core": "^3.0.2", "@material-ui/icons": "^3.0.1", "@material-ui/lab": "^3.0.0-alpha.14", + "date-fns": "1.29.0", "docz-theme-default": "1.2.0", "hls.js": "^0.12.2", "immutability-helper": "^2.8.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e36836eb..620ed7d4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -24,9 +24,12 @@ importers: '@material-ui/lab': specifier: ^3.0.0-alpha.14 version: 3.0.0-alpha.30(@material-ui/core@3.9.4(react-dom@16.14.0(react@16.14.0))(react@16.14.0))(react-dom@16.14.0(react@16.14.0))(react@16.14.0) + date-fns: + specifier: 1.29.0 + version: 1.29.0 docz-theme-default: specifier: 1.2.0 - version: 1.2.0(@babel/core@7.25.2)(encoding@0.1.13)(react-dom@16.14.0(react@16.14.0))(react@16.14.0) + version: 1.2.0(@babel/core@7.4.4)(encoding@0.1.13)(react-dom@16.14.0(react@16.14.0))(react@16.14.0) hls.js: specifier: ^0.12.2 version: 0.12.4 @@ -96,25 +99,40 @@ importers: version: 1.1293.0 '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.1(vite@5.4.21(@types/node@22.5.1)(sass-embedded@1.77.8)) + version: 4.3.1(vite@5.4.21(@types/node@22.5.1)(sass-embedded@1.77.8)(sass@1.97.3)) '@vitest/coverage-v8': specifier: ^2.0.5 - version: 2.0.5(vitest@2.0.5(@types/node@22.5.1)(sass-embedded@1.77.8)) + version: 2.0.5(vitest@2.0.5(@types/node@22.5.1)(sass-embedded@1.77.8)(sass@1.97.3)) + css-loader: + specifier: ^4.3.0 + version: 4.3.0(webpack@4.47.0) + docz: + specifier: 1.2.0 + version: 1.2.0(encoding@0.1.13)(react-dom@16.14.0(react@16.14.0))(react@16.14.0) js-yaml: specifier: 4.1.1 version: 4.1.1 redux-saga-test-plan: specifier: ^3.7.0 version: 3.7.0(redux-saga@0.16.2) + sass: + specifier: ^1.32.0 + version: 1.97.3 sass-embedded: specifier: ^1.77.8 version: 1.77.8 + sass-loader: + specifier: ^10.2.0 + version: 10.5.2(sass@1.97.3)(webpack@4.47.0) + style-loader: + specifier: ^2.0.0 + version: 2.0.0(webpack@4.47.0) vite: specifier: ^5.4.21 - version: 5.4.21(@types/node@22.5.1)(sass-embedded@1.77.8) + version: 5.4.21(@types/node@22.5.1)(sass-embedded@1.77.8)(sass@1.97.3) vitest: specifier: ^2.0.5 - version: 2.0.5(@types/node@22.5.1)(sass-embedded@1.77.8) + version: 2.0.5(@types/node@22.5.1)(sass-embedded@1.77.8)(sass@1.97.3) packages: @@ -1197,6 +1215,88 @@ packages: resolution: {integrity: sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==} engines: {node: '>= 6'} + '@parcel/watcher-android-arm64@2.5.6': + resolution: {integrity: sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [android] + + '@parcel/watcher-darwin-arm64@2.5.6': + resolution: {integrity: sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [darwin] + + '@parcel/watcher-darwin-x64@2.5.6': + resolution: {integrity: sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [darwin] + + '@parcel/watcher-freebsd-x64@2.5.6': + resolution: {integrity: sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [freebsd] + + '@parcel/watcher-linux-arm-glibc@2.5.6': + resolution: {integrity: sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + + '@parcel/watcher-linux-arm-musl@2.5.6': + resolution: {integrity: sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + + '@parcel/watcher-linux-arm64-glibc@2.5.6': + resolution: {integrity: sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + + '@parcel/watcher-linux-arm64-musl@2.5.6': + resolution: {integrity: sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + + '@parcel/watcher-linux-x64-glibc@2.5.6': + resolution: {integrity: sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + + '@parcel/watcher-linux-x64-musl@2.5.6': + resolution: {integrity: sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + + '@parcel/watcher-win32-arm64@2.5.6': + resolution: {integrity: sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [win32] + + '@parcel/watcher-win32-ia32@2.5.6': + resolution: {integrity: sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==} + engines: {node: '>= 10.0.0'} + cpu: [ia32] + os: [win32] + + '@parcel/watcher-win32-x64@2.5.6': + resolution: {integrity: sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [win32] + + '@parcel/watcher@2.5.6': + resolution: {integrity: sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==} + engines: {node: '>= 10.0.0'} + '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -2085,6 +2185,10 @@ packages: resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} engines: {node: '>=6'} + camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + camelize@1.0.1: resolution: {integrity: sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==} @@ -2137,12 +2241,15 @@ packages: chokidar@2.1.8: resolution: {integrity: sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==} - deprecated: Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + chownr@1.1.4: resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} @@ -2394,6 +2501,12 @@ packages: resolution: {integrity: sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==} engines: {node: '>=4'} + css-loader@4.3.0: + resolution: {integrity: sha512-rdezjCjScIrsL8BSYszgT4s476IcNKt6yX69t0pHjJVnPUTDpn4WfIpDQTN3wCJvUvfsz/mFjuGOekf3PY3NUg==} + engines: {node: '>= 10.13.0'} + peerDependencies: + webpack: ^4.27.0 || ^5.0.0 + css-select-base-adapter@0.1.1: resolution: {integrity: sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==} @@ -2418,6 +2531,11 @@ packages: resolution: {integrity: sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==} engines: {node: '>= 6'} + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + csso@4.2.0: resolution: {integrity: sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==} engines: {node: '>=8.0.0'} @@ -2451,6 +2569,9 @@ packages: resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==} engines: {node: '>= 0.4'} + date-fns@1.29.0: + resolution: {integrity: sha512-lbTXWZ6M20cWH8N9S6afb0SBm6tMk+uUg6z3MqHPKE9atmsY3kJkTm8vKe93izJ2B2+q5MV990sM2CHgtAZaOw==} + debounce@1.2.1: resolution: {integrity: sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==} @@ -2572,6 +2693,10 @@ packages: detab@2.0.4: resolution: {integrity: sha512-8zdsQA5bIkoRECvCrNKPla84lyoR7DSAyf7p0YgXzBO9PDJx8KntPUay7NS6yp+KdxdVtiE5SpHKtbp2ZQyA9g==} + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + detect-node@2.1.0: resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==} @@ -2617,8 +2742,8 @@ packages: docz-utils@1.2.0: resolution: {integrity: sha512-1iuvNJr1PXevzi1hIYyAnytyeITgHzJNBQ1gcbFRWA4+4jf6sU4YLOazyiOFk5Kb1dpppaMvmygKvt+eGy4p0Q==} - docz@1.3.2: - resolution: {integrity: sha512-A6z35Ft6nlLvp3HvZupwwpW9QRQlA0bKojr5gJZAzr1h7jO+sff7kLzixikcQIDjPVj5Rp734XqmFr/Z67ZTyg==} + docz@1.2.0: + resolution: {integrity: sha512-E9X9ffYtv3W/jXVdOi24oeQ4zM6ZCCgp4ls3CIfMRPjR2ZB02qCzIDzXa7pjQyqUVpQAerQ98CVjR1LjLJwj6Q==} hasBin: true peerDependencies: react: ^16.8.0 @@ -3163,7 +3288,7 @@ packages: glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me global-modules@2.0.0: resolution: {integrity: sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==} @@ -3395,6 +3520,10 @@ packages: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} + icss-utils@4.1.1: + resolution: {integrity: sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==} + engines: {node: '>= 6'} + ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} @@ -3413,6 +3542,9 @@ packages: immutable@4.3.7: resolution: {integrity: sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==} + immutable@5.1.4: + resolution: {integrity: sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==} + import-fresh@2.0.0: resolution: {integrity: sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==} engines: {node: '>=4'} @@ -3871,6 +4003,10 @@ packages: resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} engines: {node: '>=0.10.0'} + klona@2.0.6: + resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} + engines: {node: '>= 8'} + langs@2.0.0: resolution: {integrity: sha512-v4pxOBEQVN1WBTfB1crhTtxzNLZU9HPWgadlwzWKISJtt6Ku/CnpBrwVy+jFv8StjxsPfwPFzO0CMwdZLJ0/BA==} @@ -4290,6 +4426,9 @@ packages: no-case@2.3.2: resolution: {integrity: sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==} + node-addon-api@7.1.1: + resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} + node-dir@0.1.17: resolution: {integrity: sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==} engines: {node: '>= 0.10.5'} @@ -4601,6 +4740,9 @@ packages: perfect-scrollbar@1.5.5: resolution: {integrity: sha512-dzalfutyP3e/FOpdlhVryN4AJ5XDVauVWxybSkLZmakFE2sS3y3pc4JnSprw8tGmHvkaG5Edr5T7LBTZ+WWU2g==} + picocolors@0.2.1: + resolution: {integrity: sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -4608,6 +4750,10 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + pify@2.3.0: resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} engines: {node: '>=0.10.0'} @@ -4681,9 +4827,35 @@ packages: resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} engines: {node: '>= 0.4'} + postcss-modules-extract-imports@2.0.0: + resolution: {integrity: sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==} + engines: {node: '>= 6'} + + postcss-modules-local-by-default@3.0.3: + resolution: {integrity: sha512-e3xDq+LotiGesympRlKNgaJ0PCzoUIdpH0dj47iWAui/kyTgh3CiAr1qP54uodmJhl6p9rN6BoNcdEDVJx9RDw==} + engines: {node: '>= 6'} + + postcss-modules-scope@2.2.0: + resolution: {integrity: sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ==} + engines: {node: '>= 6'} + + postcss-modules-values@3.0.0: + resolution: {integrity: sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg==} + + postcss-selector-parser@6.1.2: + resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} + engines: {node: '>=4'} + postcss-value-parser@3.3.1: resolution: {integrity: sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==} + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + + postcss@7.0.39: + resolution: {integrity: sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==} + engines: {node: '>=6.0.0'} + postcss@8.5.6: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} @@ -4997,6 +5169,10 @@ packages: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + recast@0.17.6: resolution: {integrity: sha512-yoQRMRrK1lszNtbkGyM4kN45AwylV5hMiuEveUBlxytUViWevjvX6w+tzJt1LH4cfUhWt4NZvy3ThIhu6+m5wQ==} engines: {node: '>= 4'} @@ -5373,6 +5549,27 @@ packages: resolution: {integrity: sha512-WGXA6jcaoBo5Uhw0HX/s6z/sl3zyYQ7ZOnLOJzqwpctFcFmU4L07zn51e2VSkXXFpQZFAdMZNqOGz/7h/fvcRA==} engines: {node: '>=16.0.0'} + sass-loader@10.5.2: + resolution: {integrity: sha512-vMUoSNOUKJILHpcNCCyD23X34gve1TS7Rjd9uXHeKqhvBG39x6XbswFDtpbTElj6XdMFezoWhkh5vtKudf2cgQ==} + engines: {node: '>= 10.13.0'} + peerDependencies: + fibers: '>= 3.1.0' + node-sass: ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 + sass: ^1.3.0 + webpack: ^4.36.0 || ^5.0.0 + peerDependenciesMeta: + fibers: + optional: true + node-sass: + optional: true + sass: + optional: true + + sass@1.97.3: + resolution: {integrity: sha512-fDz1zJpd5GycprAbu4Q2PV/RprsRtKC/0z82z0JLgdytmcq0+ujJbJ/09bPGDxCLkKY3Np5cRAOcWiVkLXJURg==} + engines: {node: '>=14.0.0'} + hasBin: true + sax@1.2.4: resolution: {integrity: sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==} @@ -5387,6 +5584,10 @@ packages: resolution: {integrity: sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==} engines: {node: '>= 8.9.0'} + schema-utils@3.3.0: + resolution: {integrity: sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==} + engines: {node: '>= 10.13.0'} + select-hose@2.0.0: resolution: {integrity: sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==} @@ -5540,10 +5741,6 @@ packages: source-list-map@2.0.1: resolution: {integrity: sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==} - source-map-js@1.2.0: - resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} - engines: {node: '>=0.10.0'} - source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -5736,6 +5933,12 @@ packages: resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} engines: {node: '>=0.10.0'} + style-loader@2.0.0: + resolution: {integrity: sha512-Z0gYUJmzZ6ZdRUqpg1r8GsaFKypE+3xAzuFeMuoHgjc9KZv3wMyCRjQIWEbhoFSq7+7yoHXySDJyyWQaPajeiQ==} + engines: {node: '>= 10.13.0'} + peerDependencies: + webpack: ^4.0.0 || ^5.0.0 + style-to-object@0.3.0: resolution: {integrity: sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA==} @@ -6544,9 +6747,9 @@ snapshots: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 - '@babel/cli@7.25.6(@babel/core@7.4.4)': + '@babel/cli@7.25.6(@babel/core@7.25.2)': dependencies: - '@babel/core': 7.4.4 + '@babel/core': 7.25.2 '@jridgewell/trace-mapping': 0.3.25 commander: 6.2.1 convert-source-map: 2.0.0 @@ -7053,7 +7256,7 @@ snapshots: '@babel/plugin-proposal-object-rest-spread@7.12.1(@babel/core@7.12.9)': dependencies: '@babel/core': 7.12.9 - '@babel/helper-plugin-utils': 7.10.4 + '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.12.9) '@babel/plugin-transform-parameters': 7.24.7(@babel/core@7.12.9) @@ -7217,6 +7420,11 @@ snapshots: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-jsx@7.24.7(@babel/core@7.4.4)': + dependencies: + '@babel/core': 7.4.4 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-jsx@7.24.7(@babel/core@7.9.0)': dependencies: '@babel/core': 7.9.0 @@ -8066,6 +8274,11 @@ snapshots: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-react-display-name@7.24.7(@babel/core@7.9.0)': + dependencies: + '@babel/core': 7.9.0 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-react-display-name@7.8.3(@babel/core@7.9.0)': dependencies: '@babel/core': 7.9.0 @@ -8611,7 +8824,7 @@ snapshots: dependencies: '@babel/core': 7.9.0 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-react-display-name': 7.8.3(@babel/core@7.9.0) + '@babel/plugin-transform-react-display-name': 7.24.7(@babel/core@7.9.0) '@babel/plugin-transform-react-jsx': 7.25.2(@babel/core@7.9.0) '@babel/plugin-transform-react-jsx-development': 7.24.7(@babel/core@7.9.0) '@babel/plugin-transform-react-jsx-self': 7.24.7(@babel/core@7.9.0) @@ -8927,6 +9140,67 @@ snapshots: '@nodelib/fs.stat@1.1.3': {} + '@parcel/watcher-android-arm64@2.5.6': + optional: true + + '@parcel/watcher-darwin-arm64@2.5.6': + optional: true + + '@parcel/watcher-darwin-x64@2.5.6': + optional: true + + '@parcel/watcher-freebsd-x64@2.5.6': + optional: true + + '@parcel/watcher-linux-arm-glibc@2.5.6': + optional: true + + '@parcel/watcher-linux-arm-musl@2.5.6': + optional: true + + '@parcel/watcher-linux-arm64-glibc@2.5.6': + optional: true + + '@parcel/watcher-linux-arm64-musl@2.5.6': + optional: true + + '@parcel/watcher-linux-x64-glibc@2.5.6': + optional: true + + '@parcel/watcher-linux-x64-musl@2.5.6': + optional: true + + '@parcel/watcher-win32-arm64@2.5.6': + optional: true + + '@parcel/watcher-win32-ia32@2.5.6': + optional: true + + '@parcel/watcher-win32-x64@2.5.6': + optional: true + + '@parcel/watcher@2.5.6': + dependencies: + detect-libc: 2.1.2 + is-glob: 4.0.3 + node-addon-api: 7.1.1 + picomatch: 4.0.3 + optionalDependencies: + '@parcel/watcher-android-arm64': 2.5.6 + '@parcel/watcher-darwin-arm64': 2.5.6 + '@parcel/watcher-darwin-x64': 2.5.6 + '@parcel/watcher-freebsd-x64': 2.5.6 + '@parcel/watcher-linux-arm-glibc': 2.5.6 + '@parcel/watcher-linux-arm-musl': 2.5.6 + '@parcel/watcher-linux-arm64-glibc': 2.5.6 + '@parcel/watcher-linux-arm64-musl': 2.5.6 + '@parcel/watcher-linux-x64-glibc': 2.5.6 + '@parcel/watcher-linux-x64-musl': 2.5.6 + '@parcel/watcher-win32-arm64': 2.5.6 + '@parcel/watcher-win32-ia32': 2.5.6 + '@parcel/watcher-win32-x64': 2.5.6 + optional: true + '@pkgjs/parseargs@0.11.0': optional: true @@ -9187,21 +9461,21 @@ snapshots: '@types/vfile@3.0.2': dependencies: '@types/node': 22.5.1 - '@types/unist': 2.0.11 + '@types/unist': 3.0.3 '@types/vfile-message': 2.0.0 - '@vitejs/plugin-react@4.3.1(vite@5.4.21(@types/node@22.5.1)(sass-embedded@1.77.8))': + '@vitejs/plugin-react@4.3.1(vite@5.4.21(@types/node@22.5.1)(sass-embedded@1.77.8)(sass@1.97.3))': dependencies: '@babel/core': 7.25.2 '@babel/plugin-transform-react-jsx-self': 7.24.7(@babel/core@7.25.2) '@babel/plugin-transform-react-jsx-source': 7.24.7(@babel/core@7.25.2) '@types/babel__core': 7.20.5 react-refresh: 0.14.2 - vite: 5.4.21(@types/node@22.5.1)(sass-embedded@1.77.8) + vite: 5.4.21(@types/node@22.5.1)(sass-embedded@1.77.8)(sass@1.97.3) transitivePeerDependencies: - supports-color - '@vitest/coverage-v8@2.0.5(vitest@2.0.5(@types/node@22.5.1)(sass-embedded@1.77.8))': + '@vitest/coverage-v8@2.0.5(vitest@2.0.5(@types/node@22.5.1)(sass-embedded@1.77.8)(sass@1.97.3))': dependencies: '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 0.2.3 @@ -9215,7 +9489,7 @@ snapshots: std-env: 3.7.0 test-exclude: 7.0.1 tinyrainbow: 1.2.0 - vitest: 2.0.5(@types/node@22.5.1)(sass-embedded@1.77.8) + vitest: 2.0.5(@types/node@22.5.1)(sass-embedded@1.77.8)(sass@1.97.3) transitivePeerDependencies: - supports-color @@ -9577,9 +9851,9 @@ snapshots: esutils: 2.0.3 js-tokens: 3.0.2 - babel-core@7.0.0-bridge.0(@babel/core@7.4.4): + babel-core@7.0.0-bridge.0(@babel/core@7.25.2): dependencies: - '@babel/core': 7.4.4 + '@babel/core': 7.25.2 babel-loader@8.3.0(@babel/core@7.4.4)(webpack@4.47.0): dependencies: @@ -9598,11 +9872,11 @@ snapshots: babel-plugin-export-metadata@1.2.0: dependencies: - '@babel/cli': 7.25.6(@babel/core@7.4.4) - '@babel/core': 7.4.4 - '@babel/preset-env': 7.25.4(@babel/core@7.4.4) + '@babel/cli': 7.25.6(@babel/core@7.25.2) + '@babel/core': 7.25.2 + '@babel/preset-env': 7.25.4(@babel/core@7.25.2) '@babel/template': 7.25.0 - babel-core: 7.0.0-bridge.0(@babel/core@7.4.4) + babel-core: 7.0.0-bridge.0(@babel/core@7.25.2) lodash: 4.17.21 transitivePeerDependencies: - supports-color @@ -9669,14 +9943,14 @@ snapshots: transitivePeerDependencies: - supports-color - babel-plugin-styled-components@2.1.4(@babel/core@7.25.2)(styled-components@4.4.1(@babel/core@7.25.2)(react-dom@16.14.0(react@16.14.0))(react@16.14.0))(supports-color@5.5.0): + babel-plugin-styled-components@2.1.4(@babel/core@7.4.4)(styled-components@4.4.1(@babel/core@7.4.4)(react-dom@16.14.0(react@16.14.0))(react@16.14.0))(supports-color@5.5.0): dependencies: '@babel/helper-annotate-as-pure': 7.24.7 '@babel/helper-module-imports': 7.24.7(supports-color@5.5.0) - '@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.4.4) lodash: 4.17.21 picomatch: 2.3.1 - styled-components: 4.4.1(@babel/core@7.25.2)(react-dom@16.14.0(react@16.14.0))(react@16.14.0) + styled-components: 4.4.1(@babel/core@7.4.4)(react-dom@16.14.0(react@16.14.0))(react@16.14.0) transitivePeerDependencies: - '@babel/core' - supports-color @@ -9995,6 +10269,8 @@ snapshots: camelcase@5.3.1: {} + camelcase@6.3.0: {} + camelize@1.0.1: {} caniuse-lite@1.0.30001655: {} @@ -10075,6 +10351,10 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + chokidar@4.0.3: + dependencies: + readdirp: 4.1.2 + chownr@1.1.4: {} chrome-trace-event@1.0.4: {} @@ -10373,6 +10653,22 @@ snapshots: css-color-keywords@1.0.0: {} + css-loader@4.3.0(webpack@4.47.0): + dependencies: + camelcase: 6.3.0 + cssesc: 3.0.0 + icss-utils: 4.1.1 + loader-utils: 2.0.4 + postcss: 7.0.39 + postcss-modules-extract-imports: 2.0.0 + postcss-modules-local-by-default: 3.0.3 + postcss-modules-scope: 2.2.0 + postcss-modules-values: 3.0.0 + postcss-value-parser: 4.2.0 + schema-utils: 2.7.1 + semver: 7.6.3 + webpack: 4.47.0 + css-select-base-adapter@0.1.1: {} css-select@2.1.0: @@ -10404,6 +10700,8 @@ snapshots: css-what@3.4.2: {} + cssesc@3.0.0: {} + csso@4.2.0: dependencies: css-tree: 1.1.3 @@ -10441,6 +10739,8 @@ snapshots: es-errors: 1.3.0 is-data-view: 1.0.1 + date-fns@1.29.0: {} + debounce@1.2.1: {} debug@2.6.9(supports-color@6.1.0): @@ -10560,11 +10860,14 @@ snapshots: dependencies: repeat-string: 1.6.1 + detect-libc@2.1.2: + optional: true + detect-node@2.1.0: {} detect-port-alt@1.1.6: dependencies: - address: 1.1.2 + address: 1.2.2 debug: 2.6.9(supports-color@6.1.0) transitivePeerDependencies: - supports-color @@ -10679,14 +10982,14 @@ snapshots: - webpack-cli - webpack-command - docz-theme-default@1.2.0(@babel/core@7.25.2)(encoding@0.1.13)(react-dom@16.14.0(react@16.14.0))(react@16.14.0): + docz-theme-default@1.2.0(@babel/core@7.4.4)(encoding@0.1.13)(react-dom@16.14.0(react@16.14.0))(react@16.14.0): dependencies: '@loadable/component': 5.16.4(react@16.14.0) '@reach/router': 1.3.4(react-dom@16.14.0(react@16.14.0))(react@16.14.0) '@tippy.js/react': 2.2.3(react-dom@16.14.0(react@16.14.0))(react@16.14.0) codemirror: 5.65.17 copy-text-to-clipboard: 2.2.0 - docz: 1.3.2(encoding@0.1.13)(react-dom@16.14.0(react@16.14.0))(react@16.14.0) + docz: 1.2.0(encoding@0.1.13)(react-dom@16.14.0(react@16.14.0))(react@16.14.0) facepaint: 1.2.1 hotkeys-js: 3.13.7 lodash: 4.17.21 @@ -10699,7 +11002,7 @@ snapshots: react-feather: 1.1.6(prop-types@15.7.2)(react@16.14.0) react-live: 2.0.1(react-dom@16.14.0(react@16.14.0))(react@16.14.0) react-perfect-scrollbar: 1.5.8(react-dom@16.14.0(react@16.14.0))(react@16.14.0) - styled-components: 4.4.1(@babel/core@7.25.2)(react-dom@16.14.0(react@16.14.0))(react@16.14.0) + styled-components: 4.4.1(@babel/core@7.4.4)(react-dom@16.14.0(react@16.14.0))(react@16.14.0) typescript: 3.3.4000 transitivePeerDependencies: - '@babel/core' @@ -10742,7 +11045,7 @@ snapshots: - encoding - supports-color - docz@1.3.2(encoding@0.1.13)(react-dom@16.14.0(react@16.14.0))(react@16.14.0): + docz@1.2.0(encoding@0.1.13)(react-dom@16.14.0(react@16.14.0))(react@16.14.0): dependencies: '@loadable/component': 5.16.4(react@16.14.0) '@mdx-js/react': 1.6.22(react@16.14.0) @@ -11765,6 +12068,10 @@ snapshots: dependencies: safer-buffer: 2.1.2 + icss-utils@4.1.1: + dependencies: + postcss: 7.0.39 + ieee754@1.2.1: {} iferr@0.1.5: {} @@ -11779,6 +12086,8 @@ snapshots: immutable@4.3.7: {} + immutable@5.1.4: {} + import-fresh@2.0.0: dependencies: caller-path: 2.0.0 @@ -12184,6 +12493,8 @@ snapshots: kind-of@6.0.3: {} + klona@2.0.6: {} + langs@2.0.0: {} lazy-cache@0.2.7: {} @@ -12330,7 +12641,7 @@ snapshots: dependencies: '@babel/parser': 7.25.6 '@babel/types': 7.25.6 - source-map-js: 1.2.0 + source-map-js: 1.2.1 make-dir@2.1.0: dependencies: @@ -12638,6 +12949,9 @@ snapshots: dependencies: lower-case: 1.1.4 + node-addon-api@7.1.1: + optional: true + node-dir@0.1.17: dependencies: minimatch: 3.1.2 @@ -12961,10 +13275,15 @@ snapshots: perfect-scrollbar@1.5.5: {} + picocolors@0.2.1: {} + picocolors@1.1.1: {} picomatch@2.3.1: {} + picomatch@4.0.3: + optional: true + pify@2.3.0: {} pify@3.0.0: {} @@ -13051,8 +13370,41 @@ snapshots: possible-typed-array-names@1.0.0: {} + postcss-modules-extract-imports@2.0.0: + dependencies: + postcss: 7.0.39 + + postcss-modules-local-by-default@3.0.3: + dependencies: + icss-utils: 4.1.1 + postcss: 7.0.39 + postcss-selector-parser: 6.1.2 + postcss-value-parser: 4.2.0 + + postcss-modules-scope@2.2.0: + dependencies: + postcss: 7.0.39 + postcss-selector-parser: 6.1.2 + + postcss-modules-values@3.0.0: + dependencies: + icss-utils: 4.1.1 + postcss: 7.0.39 + + postcss-selector-parser@6.1.2: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + postcss-value-parser@3.3.1: {} + postcss-value-parser@4.2.0: {} + + postcss@7.0.39: + dependencies: + picocolors: 0.2.1 + source-map: 0.6.1 + postcss@8.5.6: dependencies: nanoid: 3.3.11 @@ -13257,7 +13609,7 @@ snapshots: react-docgen@4.1.1: dependencies: - '@babel/core': 7.4.4 + '@babel/core': 7.25.2 '@babel/runtime': 7.25.6 async: 2.6.4 commander: 2.20.3 @@ -13448,6 +13800,8 @@ snapshots: dependencies: picomatch: 2.3.1 + readdirp@4.1.2: {} + recast@0.17.6: dependencies: ast-types: 0.12.4 @@ -13885,6 +14239,25 @@ snapshots: sass-embedded-win32-ia32: 1.77.8 sass-embedded-win32-x64: 1.77.8 + sass-loader@10.5.2(sass@1.97.3)(webpack@4.47.0): + dependencies: + klona: 2.0.6 + loader-utils: 2.0.4 + neo-async: 2.6.2 + schema-utils: 3.3.0 + semver: 7.6.3 + webpack: 4.47.0 + optionalDependencies: + sass: 1.97.3 + + sass@1.97.3: + dependencies: + chokidar: 4.0.3 + immutable: 5.1.4 + source-map-js: 1.2.1 + optionalDependencies: + '@parcel/watcher': 2.5.6 + sax@1.2.4: {} scheduler@0.19.1: @@ -13904,6 +14277,12 @@ snapshots: ajv: 6.12.6 ajv-keywords: 3.5.2(ajv@6.12.6) + schema-utils@3.3.0: + dependencies: + '@types/json-schema': 7.0.15 + ajv: 6.12.6 + ajv-keywords: 3.5.2(ajv@6.12.6) + select-hose@2.0.0: {} selfsigned@1.10.14: @@ -14124,8 +14503,6 @@ snapshots: source-list-map@2.0.1: {} - source-map-js@1.2.0: {} - source-map-js@1.2.1: {} source-map-loader@0.2.4: @@ -14332,6 +14709,12 @@ snapshots: strip-json-comments@2.0.1: {} + style-loader@2.0.0(webpack@4.47.0): + dependencies: + loader-utils: 2.0.4 + schema-utils: 3.3.0 + webpack: 4.47.0 + style-to-object@0.3.0: dependencies: inline-style-parser: 0.1.1 @@ -14341,13 +14724,13 @@ snapshots: hey-listen: 1.0.8 tslib: 1.14.1 - styled-components@4.4.1(@babel/core@7.25.2)(react-dom@16.14.0(react@16.14.0))(react@16.14.0): + styled-components@4.4.1(@babel/core@7.4.4)(react-dom@16.14.0(react@16.14.0))(react@16.14.0): dependencies: '@babel/helper-module-imports': 7.24.7(supports-color@5.5.0) '@babel/traverse': 7.25.6(supports-color@5.5.0) '@emotion/is-prop-valid': 0.8.8 '@emotion/unitless': 0.7.5 - babel-plugin-styled-components: 2.1.4(@babel/core@7.25.2)(styled-components@4.4.1(@babel/core@7.25.2)(react-dom@16.14.0(react@16.14.0))(react@16.14.0))(supports-color@5.5.0) + babel-plugin-styled-components: 2.1.4(@babel/core@7.4.4)(styled-components@4.4.1(@babel/core@7.4.4)(react-dom@16.14.0(react@16.14.0))(react@16.14.0))(supports-color@5.5.0) css-to-react-native: 2.3.2 memoize-one: 5.2.1 merge-anything: 2.4.4 @@ -14874,13 +15257,13 @@ snapshots: unist-util-stringify-position: 2.0.3 vfile-message: 2.0.4 - vite-node@2.0.5(@types/node@22.5.1)(sass-embedded@1.77.8): + vite-node@2.0.5(@types/node@22.5.1)(sass-embedded@1.77.8)(sass@1.97.3): dependencies: cac: 6.7.14 debug: 4.3.6(supports-color@6.1.0) pathe: 1.1.2 tinyrainbow: 1.2.0 - vite: 5.4.21(@types/node@22.5.1)(sass-embedded@1.77.8) + vite: 5.4.21(@types/node@22.5.1)(sass-embedded@1.77.8)(sass@1.97.3) transitivePeerDependencies: - '@types/node' - less @@ -14892,7 +15275,7 @@ snapshots: - supports-color - terser - vite@5.4.21(@types/node@22.5.1)(sass-embedded@1.77.8): + vite@5.4.21(@types/node@22.5.1)(sass-embedded@1.77.8)(sass@1.97.3): dependencies: esbuild: 0.21.5 postcss: 8.5.6 @@ -14900,9 +15283,10 @@ snapshots: optionalDependencies: '@types/node': 22.5.1 fsevents: 2.3.3 + sass: 1.97.3 sass-embedded: 1.77.8 - vitest@2.0.5(@types/node@22.5.1)(sass-embedded@1.77.8): + vitest@2.0.5(@types/node@22.5.1)(sass-embedded@1.77.8)(sass@1.97.3): dependencies: '@ampproject/remapping': 2.3.0 '@vitest/expect': 2.0.5 @@ -14920,8 +15304,8 @@ snapshots: tinybench: 2.9.0 tinypool: 1.0.1 tinyrainbow: 1.2.0 - vite: 5.4.21(@types/node@22.5.1)(sass-embedded@1.77.8) - vite-node: 2.0.5(@types/node@22.5.1)(sass-embedded@1.77.8) + vite: 5.4.21(@types/node@22.5.1)(sass-embedded@1.77.8)(sass@1.97.3) + vite-node: 2.0.5(@types/node@22.5.1)(sass-embedded@1.77.8)(sass@1.97.3) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 22.5.1 diff --git a/scripts/patch-docz.js b/scripts/patch-docz.js new file mode 100644 index 00000000..f88ea469 --- /dev/null +++ b/scripts/patch-docz.js @@ -0,0 +1,71 @@ +#!/usr/bin/env node +/** + * Patch 1: Delete the nested ws@7 from docz-core and let Node resolution of ws to fall-back to + * the top-level ws@6 in node_modules. This avoids ws@7's argument validation that rejects docz-core's + * WebSocketServer usage, while still allowing docz to use ws for live-reload in dev mode. + */ +const fs = require('fs'); +const path = require('path'); + +const nestedWsPath = path.join(__dirname, '../node_modules/docz-core/node_modules/ws'); +if (fs.existsSync(nestedWsPath)) { + fs.rmSync(nestedWsPath, { recursive: true, force: true }); + console.log('Removed nested docz-core/node_modules/ws (ws@7) — will fall back to top-level ws@6'); +} else { + console.log('docz-core/node_modules/ws not present, no action needed'); +} + +/** + * Patch 2: Restore safeLoad/safeDump compatibility aliases to js-yaml@4. + * 'remark-parse-yaml' used by docz still calls 'safeLoad', this replaces the + * stubs with real function references. + */ +const indexPath = path.join(__dirname, '../node_modules/js-yaml/index.js'); +if (!fs.existsSync(indexPath)) { + console.log('js-yaml not found, skipping patch'); + process.exit(0); +} + +const content = fs.readFileSync(indexPath, 'utf8'); + +if (content.includes("renamed('safeLoad'")) { + const patched = content + .replace( + /module\.exports\.safeLoad\s*=\s*renamed\('safeLoad',\s*'load'\);/, + "module.exports.safeLoad = loader.load;" + ) + .replace( + /module\.exports\.safeLoadAll\s*=\s*renamed\('safeLoadAll',\s*'loadAll'\);/, + "module.exports.safeLoadAll = loader.loadAll;" + ) + .replace( + /module\.exports\.safeDump\s*=\s*renamed\('safeDump',\s*'dump'\);/, + "module.exports.safeDump = dumper.dump;" + ); + fs.writeFileSync(indexPath, patched, 'utf8'); + console.log('js-yaml patched: safeLoad/safeDump restored as aliases for load/dump'); +} else { + console.log('js-yaml already patched or unexpected format, skipping'); +} + +/** + * Patch 3: Replace the hardcoded "Built with docz" footer link in docz-theme-default. + */ +for (const themeFile of ['index.js', 'index.esm.js']) { + const themeDefaultPath = path.join(__dirname, `../node_modules/docz-theme-default/dist/${themeFile}`); + if (fs.existsSync(themeDefaultPath)) { + const themeContent = fs.readFileSync(themeDefaultPath, 'utf8'); + if (themeContent.includes('href: "https://docz.site"')) { + const themePatched = themeContent.replace( + 'href: "https://docz.site"', + 'href: "https://github.com/doczjs/docz"' + ); + fs.writeFileSync(themeDefaultPath, themePatched, 'utf8'); + console.log(`docz-theme-default ${themeFile} patched: footer link updated`); + } else { + console.log(`docz-theme-default ${themeFile} footer link already patched`); + } + } else { + console.log(`docz-theme-default ${themeFile} not found, skipping footer patch`); + } +} diff --git a/src/components/AudioImporter/AudioImporter.demo.jsx b/src/components/AudioImporter/AudioImporter.demo.jsx new file mode 100644 index 00000000..3de10a83 --- /dev/null +++ b/src/components/AudioImporter/AudioImporter.demo.jsx @@ -0,0 +1,38 @@ +import React, { useRef, useState, useEffect } from 'react'; +import AudioImporter from './AudioImporter'; +import Button from '@material-ui/core/Button'; + +export const AudioImporterDemo = () => { + const [importedJSON, setImportedJSON] = useState(''); + const [isImporterOpen, setIsImporterOpen] = useState(false); + + return ( +
+ + { + setIsImporterOpen(false); + }} + onImport={(manifest) => { + setIsImporterOpen(false); + setImportedJSON(JSON.stringify(manifest, null, 2)); + }} + /> + {importedJSON && ( +
+ Manifest: +
+            {importedJSON}
+          
+
+ )} +
+ ); +}; diff --git a/src/components/AudioImporter/AudioImporter.mdx b/src/components/AudioImporter/AudioImporter.mdx index f4d93d4a..492e6af4 100644 --- a/src/components/AudioImporter/AudioImporter.mdx +++ b/src/components/AudioImporter/AudioImporter.mdx @@ -1,11 +1,12 @@ --- title: Audio importer menu: Components +edit: false --- -import { Playground, Props } from 'docz'; -import Component from '@reach/component-component'; +import { Props } from 'docz'; import AudioImporter from './AudioImporter'; -import Button from '@material-ui/core/Button'; +import { AudioImporterDemo } from './AudioImporter.demo'; +import DemoWrapper from '../docs/components/DemoWrapper/DemoWrapper'; # Audio importer Imports either a IIIF manifest, or audio source. Always returns a valid IIIF Presentation 3 manifest. @@ -21,50 +22,6 @@ Example urls: - manifest: https://api.myjson.com/bins/6bfu0 - non existing url (to test error messages): https://webaudioapi.com/samples/audio-tag/chrono.avi - - - {({ setState, state }) => ( -
- - { - setState({ - isImporterOpen:false, - }); - } - } - onImport={ - (manifest) => { - setState({ - isImporterOpen:false, - importedJSON: JSON.stringify(manifest, null, 2), - }); - } - } - /> - { - state.importedJSON && ( -
- Manifest: -
-              {state.importedJSON}
-            
-
- ) - } -
- )} -
-
+ + + diff --git a/src/components/AudioTransportBar/AudioTransportBar.jsx b/src/components/AudioTransportBar/AudioTransportBar.jsx index b7ace82b..5272dd00 100644 --- a/src/components/AudioTransportBar/AudioTransportBar.jsx +++ b/src/components/AudioTransportBar/AudioTransportBar.jsx @@ -51,7 +51,10 @@ class AudioTransportBar extends Component { keyboardListener = e => { if ( e.target && - ['INPUT', 'BUTTON', 'TEXTAREA'].indexOf(e.target.tagName) !== -1 + ( + ['INPUT', 'BUTTON', 'TEXTAREA', 'VIDEO'].indexOf(e.target.tagName) !== -1 || + e.target.getAttribute('role') === 'slider' + ) ) { return; } @@ -191,7 +194,7 @@ class AudioTransportBar extends Component { isPlaying={isPlaying} onPlay={onPlay} onPause={onPause} - disabled={this.props.isModalOpen} + disabled={this.props.isModalOpen} /> @@ -203,7 +206,7 @@ class AudioTransportBar extends Component { onZoomIn={this.props.zoomIn} onZoomOut={zoom > 1 ? this.props.zoomOut : null} onResetView={zoom !== 1 ? this.props.resetZoom : null} - disabled={this.props.isModalOpen} + disabled={this.props.isModalOpen} /> @@ -212,7 +215,7 @@ class AudioTransportBar extends Component { flipped={true} volume={volume} onVolumeChanged={onVolumeChanged} - disabled={this.props.isModalOpen} + disabled={this.props.isModalOpen} /> diff --git a/src/components/AudioTransportBar/AudioTransportBar.mdx b/src/components/AudioTransportBar/AudioTransportBar.mdx index 38a44c5c..5455ce0a 100644 --- a/src/components/AudioTransportBar/AudioTransportBar.mdx +++ b/src/components/AudioTransportBar/AudioTransportBar.mdx @@ -1,39 +1,56 @@ --- name: Audio Transport Bar menu: Components +edit: false --- -import { Playground, Props } from 'docz'; -import Component from "@reach/component-component"; +import { Props } from 'docz'; import AudioTransportBar from './AudioTransportBar'; +import DemoWrapper from '../docs/components/DemoWrapper/DemoWrapper'; # Audio Transport Bar component - - - {({ setState, state }) => ( - { - setState({ volume }); - }} - {...state} - /> - )} - - +## Audio Transport Bar Demo (Playing) + + {}} + onPause={() => {}} + onNextBubble={() => {}} + onPreviousBubble={() => {}} + onScrubAhead={() => {}} + onScrubBackwards={() => {}} + onAddBubble={() => {}} + onGroupBubble={() => {}} + onDeleteBubble={() => {}} + onAddBubble={() => {}} + onAddBubble={() => {}} + onVolumeChanged={() => {}} + isModalOpen={false} + /> + - - - {({ setState, state }) => ( - { - setState({volume}); - }} - {...state} - /> - )} - - +## Audio Transport Bar Demo (Paused) + + {}} + onPause={() => {}} + onNextBubble={() => {}} + onPreviousBubble={() => {}} + onScrubAhead={() => {}} + onScrubBackwards={() => {}} + onAddBubble={() => {}} + onGroupBubble={() => {}} + onDeleteBubble={() => {}} + onAddBubble={() => {}} + onAddBubble={() => {}} + onVolumeChanged={() => {}} + isModalOpen={false} + /> + diff --git a/src/components/BubbleDisplay/BubbleDisplay.DemoPoints.js b/src/components/BubbleDisplay/BubbleDisplay.DemoPoints.js deleted file mode 100644 index 744ddae8..00000000 --- a/src/components/BubbleDisplay/BubbleDisplay.DemoPoints.js +++ /dev/null @@ -1,35 +0,0 @@ -const DEMO_POINTS = { - root: { - id: 'id-1', - startTime: 0, - endTime: 1000, - children: ['id-3', 'id-2'], - depth: 2, - label: 'Composition', - summary: 'some summary', - isSelected: false, - colour: '#C797F0', - }, - bubble1: { - id: 'id-2', - startTime: 0, - endTime: 400, - depth: 1, - label: 'Part I', - summary: 'some summary', - isSelected: false, - colour: '#A8F097', - }, - bubble2: { - id: 'id-3', - startTime: 400, - endTime: 1000, - depth: 1, - label: 'Part II', - summary: 'some summary', - isSelected: false, - colour: '#A8F097', - }, -}; - -export default DEMO_POINTS; diff --git a/src/components/BubbleDisplay/BubbleDisplay.demo.jsx b/src/components/BubbleDisplay/BubbleDisplay.demo.jsx new file mode 100644 index 00000000..3e4d9d6e --- /dev/null +++ b/src/components/BubbleDisplay/BubbleDisplay.demo.jsx @@ -0,0 +1,103 @@ +import React from 'react'; +import BubbleDisplay from './BubbleDisplay'; +import SingleBubble from '../SingleBubble/SingleBubble'; +import { colourPalettes } from '../../config'; + +const POINTS = { + 'id-1': { + id: 'id-1', + startTime: 0, + endTime: 1000, + depth: 2, + label: 'Composition', + summary: 'some summary', + isSelected: false, + colour: '#C797F0', + }, + 'id-2': { + id: 'id-2', + startTime: 0, + endTime: 400, + depth: 1, + label: 'Part I', + summary: 'some summary', + isSelected: false, + colour: '#A8F097', + }, + 'id-3': { + id: 'id-3', + startTime: 400, + endTime: 1000, + depth: 1, + label: 'Part II', + summary: 'some summary', + isSelected: false, + colour: '#A8F097', + }, +}; + +const noop = () => {}; + +const renderBubbles = points => + points.map(bubble => ( + + )); + +export function BubbleDisplayDemo() { + return ( + + {renderBubbles} + + ); +} + +export function BubbleDisplayZoomedDemo() { + return ( + + {renderBubbles} + + ); +} + +export function BubbleDisplayClickDemo() { + return ( + + {points => + points.map(bubble => ( + { + alert(JSON.stringify(point)); + }} + /> + )) + } + + ); +} diff --git a/src/components/BubbleDisplay/BubbleDisplay.mdx b/src/components/BubbleDisplay/BubbleDisplay.mdx index ab06b8fa..3878d53e 100644 --- a/src/components/BubbleDisplay/BubbleDisplay.mdx +++ b/src/components/BubbleDisplay/BubbleDisplay.mdx @@ -1,57 +1,31 @@ --- title: Bubble Display menu: Components +edit: false --- # Bubble display Handles the rendering of many bubbles and the scrubber. You need to pass a render function to use. **Still some unknowns with how this will work, and its responsibilities** -import { Playground, Props } from 'docz'; +import { Props } from 'docz'; import BubbleDisplay from './BubbleDisplay'; -import DEMO_POINTS from './BubbleDisplay.DemoPoints'; -import SingleBubble from '../SingleBubble/SingleBubble'; +import { BubbleDisplayDemo, BubbleDisplayZoomedDemo, BubbleDisplayClickDemo } from './BubbleDisplay.demo'; +import DemoWrapper from '../docs/components/DemoWrapper/DemoWrapper'; - - - + ## Bubble Display Demo - - - {points=>points.map(bubble => )} - - + + + ## Bubble Display Zoomed Demo - - - {points=>points.map(bubble => )} - - + + + ## Bubble Display Click Event Demo - - - {points=>points.map(bubble => {alert(JSON.stringify(point));}}/>)} - - - + + + diff --git a/src/components/BubbleEditor/BubbleEditor.mdx b/src/components/BubbleEditor/BubbleEditor.mdx index f5ceeeaf..8c0bb54c 100644 --- a/src/components/BubbleEditor/BubbleEditor.mdx +++ b/src/components/BubbleEditor/BubbleEditor.mdx @@ -1,11 +1,16 @@ --- title: Bubble Editor menu: Proof of concepts +edit: false --- # Bubble Editor This proof of concept for the bubble editor/timeline interactions. import BubbleEditor from './BubbleEditor'; +import DemoWrapper from '../docs/components/DemoWrapper/DemoWrapper'; - \ No newline at end of file +## Bubble Editor Demo + + + diff --git a/src/components/ColorPaletteSwitcher/ColorPaletteSwitcher.demo.jsx b/src/components/ColorPaletteSwitcher/ColorPaletteSwitcher.demo.jsx new file mode 100644 index 00000000..f450ab52 --- /dev/null +++ b/src/components/ColorPaletteSwitcher/ColorPaletteSwitcher.demo.jsx @@ -0,0 +1,14 @@ +import React, { useState } from 'react'; +import ColorPaletteSwitcher from './ColorPaletteSwitcher'; + +export const ColorPaletteSwitcherDemo = () => { + const [currentKey, setCurrentKey] = useState('default'); + return ( +
+ +

+ Current palette: {currentKey} +

+
+ ); +}; diff --git a/src/components/ColorPaletteSwitcher/ColorPaletteSwitcher.jsx b/src/components/ColorPaletteSwitcher/ColorPaletteSwitcher.jsx index 315408c0..fac84bb0 100644 --- a/src/components/ColorPaletteSwitcher/ColorPaletteSwitcher.jsx +++ b/src/components/ColorPaletteSwitcher/ColorPaletteSwitcher.jsx @@ -46,22 +46,24 @@ const ColorPaletteSwitcher = ({ currentKey, onChange }) => { {Object.keys(colourPalettes).map(key => { const palette = colourPalettes[key]; const isChecked = currentKey === key; - return ( - } - label={ - - } - labelPlacement="end" - className={`color-palette-switcher__option ${isChecked ? 'is-selected' : ''}`} - /> - ); + if (palette && palette.colours != undefined) { + return ( + } + label={ + + } + labelPlacement="end" + className={`color-palette-switcher__option ${isChecked ? 'is-selected' : ''}`} + /> + ); + } })} diff --git a/src/components/ColorPaletteSwitcher/ColorPaletteSwitcher.mdx b/src/components/ColorPaletteSwitcher/ColorPaletteSwitcher.mdx index 76556a7e..0a713cce 100644 --- a/src/components/ColorPaletteSwitcher/ColorPaletteSwitcher.mdx +++ b/src/components/ColorPaletteSwitcher/ColorPaletteSwitcher.mdx @@ -1,11 +1,13 @@ --- title: Color palette switcher menu: Components +edit: false --- -import { Playground, Props } from 'docz'; +import { Props } from 'docz'; import ColorPaletteSwitcher from './ColorPaletteSwitcher'; -import { PROJECT } from '../../constants/project'; +import { ColorPaletteSwitcherDemo } from './ColorPaletteSwitcher.demo'; +import DemoWrapper from '../docs/components/DemoWrapper/DemoWrapper'; # Color palette switcher Creates a keyboard accessible radio button groups for listing and selecting a desired color palette for the bubbles @@ -13,19 +15,6 @@ Creates a keyboard accessible radio button groups for listing and selecting a de ## Color Palette Switcher Demo - -
- -
-
- - -## Color Palette Switcher Demo - -
- { this.setState({ [PROJECT.COLOUR_PALETTE]: key }) }} - /> -
-
+ + + diff --git a/src/components/ColourSwatchPicker/ColourSwatchPicker.mdx b/src/components/ColourSwatchPicker/ColourSwatchPicker.mdx index 3242fee9..d296cca9 100644 --- a/src/components/ColourSwatchPicker/ColourSwatchPicker.mdx +++ b/src/components/ColourSwatchPicker/ColourSwatchPicker.mdx @@ -1,10 +1,12 @@ --- title: Colour swatch picker menu: Components +edit: false --- -import { Playground, Props } from 'docz'; +import { Props } from 'docz'; import ColourSwatchPicker from './ColourSwatchPicker'; +import DemoWrapper from '../docs/components/DemoWrapper/DemoWrapper'; # Colour swatch picker Allows you to select a colour from a configured swatch of colours. @@ -12,16 +14,12 @@ Allows you to select a colour from a configured swatch of colours. ## Colour Swatch Picker Demo - -
- -
-
- + + + ## Colour Swatch Picker Custom Palette Demo - -
- -
-
+ + + + diff --git a/src/components/ContentOverlay/ContentOverlay.demo.jsx b/src/components/ContentOverlay/ContentOverlay.demo.jsx new file mode 100644 index 00000000..627d850e --- /dev/null +++ b/src/components/ContentOverlay/ContentOverlay.demo.jsx @@ -0,0 +1,35 @@ +import React, { useRef, useState, useEffect } from 'react'; +import ContentOverlay from './ContentOverlay'; +import { ERROR_CODES } from '../../constants/canvas'; + +export const ContentOverlayErrorDemo = () => { + const containerRef = useRef(null); + const [mounted, setMounted] = useState(false); + useEffect(() => { setMounted(true); }, []); + return ( +
+ {mounted && ( + + )} +
+ ); +}; + +export const ContentOverlayLoadingDemo = () => { + const [progress, setProgress] = useState(0); + useEffect(() => { + const id = setInterval(() => setProgress(p => (p + 1) % 100), 200); + return () => clearInterval(id); + }, []); + return ( +
+ +
+ ); +}; diff --git a/src/components/ContentOverlay/ContentOverlay.jsx b/src/components/ContentOverlay/ContentOverlay.jsx index 5a60d6a8..d53feae0 100644 --- a/src/components/ContentOverlay/ContentOverlay.jsx +++ b/src/components/ContentOverlay/ContentOverlay.jsx @@ -18,7 +18,7 @@ const ContentOverlay = props => { return (
{props.error.code ? ( - + We are unable to play this content diff --git a/src/components/ContentOverlay/ContentOverlay.mdx b/src/components/ContentOverlay/ContentOverlay.mdx index 8be93d73..3a5f32d6 100644 --- a/src/components/ContentOverlay/ContentOverlay.mdx +++ b/src/components/ContentOverlay/ContentOverlay.mdx @@ -1,37 +1,27 @@ --- title: Content Overlay menu: Components +edit: false --- -import { Playground, Props } from 'docz'; -import Component from "@reach/component-component"; +import { Props } from 'docz'; import ContentOverlay from './ContentOverlay'; -import { ERROR_CODES } from '../../constants/canvas'; +import { ContentOverlayErrorDemo, ContentOverlayLoadingDemo } from './ContentOverlay.demo'; +import DemoWrapper from '../docs/components/DemoWrapper/DemoWrapper'; -# Content Overlay +# Content Overlay Error messages and loading indicators displayed using this view ## Content Overlay displaying Audio Error message - -
- -
-
+ + + + ## Content overlay displaying loading indicator - -
- - {({ setState, state }) => { - setTimeout(()=> { - setState({ progress: (state.progress + 1) % 100 }); - }, 200); - return ( - - ); - }} - -
-
+ + + + diff --git a/src/components/CurrentTimeIndicator/CurrentTimeIndicator.mdx b/src/components/CurrentTimeIndicator/CurrentTimeIndicator.mdx index c91bdbbc..44b746ee 100644 --- a/src/components/CurrentTimeIndicator/CurrentTimeIndicator.mdx +++ b/src/components/CurrentTimeIndicator/CurrentTimeIndicator.mdx @@ -1,6 +1,7 @@ --- name: Current Time Indicator menu: Components +edit: false --- import { Playground, Props } from 'docz'; @@ -30,7 +31,7 @@ import CurrentTimeIndicator from './CurrentTimeIndicator';
- +
- +
diff --git a/src/components/FileUpload/FileUpload.mdx b/src/components/FileUpload/FileUpload.mdx index 7ad12db5..a5f33783 100644 --- a/src/components/FileUpload/FileUpload.mdx +++ b/src/components/FileUpload/FileUpload.mdx @@ -1,6 +1,7 @@ --- title: File upload menu: Components +edit: false --- # File Upload @@ -10,6 +11,8 @@ import { Playground, Props } from 'docz'; +## File Upload Demo console.log(val)} /> + diff --git a/src/components/Footer/Footer.jsx b/src/components/Footer/Footer.jsx index b602a85e..2dbb9b3b 100644 --- a/src/components/Footer/Footer.jsx +++ b/src/components/Footer/Footer.jsx @@ -21,6 +21,12 @@ const Footer = () => ( }} > + {process.env.VITE_DOCS === 'true' && ( + <> + View Documentation + {' · '} + + )} Timeliner at GitHub diff --git a/src/components/Footer/Footer.mdx b/src/components/Footer/Footer.mdx index ec96b28c..c98df776 100644 --- a/src/components/Footer/Footer.mdx +++ b/src/components/Footer/Footer.mdx @@ -1,9 +1,10 @@ --- title: Footer menu: Components +edit: false --- -import { Playground, Props } from 'docz'; +import { Playground } from 'docz'; import Footer from './Footer'; # Footer diff --git a/src/components/IIIFAvProvider/IIIFAvProvider.mdx b/src/components/IIIFAvProvider/IIIFAvProvider.mdx index b7df78fa..7e949dfc 100644 --- a/src/components/IIIFAvProvider/IIIFAvProvider.mdx +++ b/src/components/IIIFAvProvider/IIIFAvProvider.mdx @@ -1,11 +1,15 @@ --- title: IIIF AV Provider menu: Proof of concepts +edit: false --- # IIIF AV Provider This proof of concept reads in a Presentation 3 manifest and lets you play back the audio content of it. import IIIFAvProvider from './IIIFAvProvider'; +import DemoWrapper from '../docs/components/DemoWrapper/DemoWrapper'; - \ No newline at end of file + + + diff --git a/src/components/KeyboardControlsProvider/KeyboardControlsProvider.demo.jsx b/src/components/KeyboardControlsProvider/KeyboardControlsProvider.demo.jsx new file mode 100644 index 00000000..27b3a173 --- /dev/null +++ b/src/components/KeyboardControlsProvider/KeyboardControlsProvider.demo.jsx @@ -0,0 +1,17 @@ +import React, { useState } from 'react'; +import KeyboardControlsProvider from './KeyboardControlsProvider'; + +export const KeyboardControlsProviderDemo = () => { + const [lastKey, setLastKey] = useState(''); + return ( +
+ setLastKey(keyCombo), + 'alt+a': () => setLastKey('special alt a handler'), + }} + /> +

Last key pressed: {lastKey}

+
+ ); +}; diff --git a/src/components/KeyboardControlsProvider/KeyboardControlsProvider.mdx b/src/components/KeyboardControlsProvider/KeyboardControlsProvider.mdx index eef202ab..46ef3e1a 100644 --- a/src/components/KeyboardControlsProvider/KeyboardControlsProvider.mdx +++ b/src/components/KeyboardControlsProvider/KeyboardControlsProvider.mdx @@ -1,11 +1,13 @@ --- -title: Keyboard Controls Provider +title: Keyboard Controls Provider menu: Components +edit: false --- -import { Playground, Props } from 'docz'; -import Component from '@reach/component-component'; +import { Props } from 'docz'; import KeyboardControlsProvider from './KeyboardControlsProvider'; +import { KeyboardControlsProviderDemo } from './KeyboardControlsProvider.demo'; +import DemoWrapper from '../docs/components/DemoWrapper/DemoWrapper'; # Keyboard Controls Provider Handles the keyboard events @@ -14,24 +16,9 @@ Handles the keyboard events ## Keyboard Controls Provider Demo -This demonstration shows how to configure the key commands for the Keyboard Controls Provider. +This demonstration shows how to configure the key commands for the Keyboard Controls Provider. The `default` is the default fallback for all key combinations not defined in the commands config object. - - - {({ setState, state }) => { - return ( -
- setState({lastKey: keyCombo}), - 'alt+a': () => setState({lastKey: 'special alt a handler'}), - }} - /> -

Last key pressed:{state.lastKey}

-
- ); - }} -
-
- + + + diff --git a/src/components/LoadingIndicator/LoadingIndicator.demo.jsx b/src/components/LoadingIndicator/LoadingIndicator.demo.jsx new file mode 100644 index 00000000..27cf5f75 --- /dev/null +++ b/src/components/LoadingIndicator/LoadingIndicator.demo.jsx @@ -0,0 +1,18 @@ +import React, { useState, useEffect } from 'react'; +import LoadingIndicator from './LoadingIndicator'; + +export const LoadingIndicatorProgressDemo = () => { + const [progress, setProgress] = useState(0); + useEffect(() => { + const id = setInterval(() => { + setProgress(p => (p + 1) % 100); + }, 500); + return () => clearInterval(id); + }, []); + return ( +
+ + {progress} +
+ ); +}; diff --git a/src/components/LoadingIndicator/LoadingIndicator.mdx b/src/components/LoadingIndicator/LoadingIndicator.mdx index e9894ed2..507524c6 100644 --- a/src/components/LoadingIndicator/LoadingIndicator.mdx +++ b/src/components/LoadingIndicator/LoadingIndicator.mdx @@ -1,11 +1,13 @@ --- title: Loading indicator menu: Components +edit: false --- -import { Playground, Props } from 'docz'; -import Component from "@reach/component-component"; +import { Props } from 'docz'; import LoadingIndicator from './LoadingIndicator'; +import { LoadingIndicatorProgressDemo } from './LoadingIndicator.demo'; +import DemoWrapper from '../docs/components/DemoWrapper/DemoWrapper'; # Loading indicator Displays loading progress. @@ -14,25 +16,12 @@ Displays loading progress. ## Loading Indicator Indefinite Demo - + - - + ## Loading Indicator with Current Progress Value - - - {({ setState, state }) => { - setTimeout(()=> { - setState({ progress: (state.progress + 1) % 100 }); - }, 500); - return ( -
- - {state.progress} -
- ); - }} -
-
+ + + diff --git a/src/components/Metadata/Metadata.demo.jsx b/src/components/Metadata/Metadata.demo.jsx new file mode 100644 index 00000000..bdf642be --- /dev/null +++ b/src/components/Metadata/Metadata.demo.jsx @@ -0,0 +1,65 @@ +import React from 'react'; +import Metadata from './Metadata'; +import { colourPalettes } from '../../config'; + +const RANGES = [ + { + id: 'id-1', + startTime: 0, + endTime: 60 * 1000, + depth: 1, + label: 'Intro', + summary: 'Some summary for the intro section.', + isSelected: false, + colour: '#C797F0', + }, + { + id: 'id-2', + startTime: 0, + endTime: 40 * 1000, + depth: 2, + label: 'Part I', + summary: 'Some summary for part one.', + isSelected: false, + colour: '#A8F097', + }, + { + id: 'id-3', + startTime: 40 * 1000, + endTime: 60 * 1000, + depth: 2, + label: 'Part II', + summary: 'Some summary for part two.', + isSelected: false, + colour: '#A8F097', + }, +]; + +const noop = () => {}; + +export function MetadataDemo() { + return ( + + ); +} diff --git a/src/components/Metadata/Metadata.jsx b/src/components/Metadata/Metadata.jsx index c346a5a5..5efccddb 100644 --- a/src/components/Metadata/Metadata.jsx +++ b/src/components/Metadata/Metadata.jsx @@ -109,14 +109,14 @@ const Metadata = props => { key={marker.id} highlight={false} marker={marker} - onDeleteMarker={() => { - props.deleteMarker(marker.id); - props.updateProjectStatus(false); - } + onDeleteMarker={() => { + props.deleteMarker(marker.id); + props.updateProjectStatus(false); + } } onSaveMarker={data => props.updateMarker(marker.id, data)} onGoToMarker={() => props.setCurrentTime(marker.time)} - runTime={props.runTime} + runTime={props.runTime} /> ); })} @@ -133,10 +133,10 @@ const Metadata = props => { > Video Playback -
- )} + )}
{ canErase={props.canErase} undoAll={props.undoAll} hasResource={props.hasResource} - isModalOpen={props.isModalOpen} + isModalOpen={props.isModalOpen} /> )}
diff --git a/src/components/Metadata/Metadata.mdx b/src/components/Metadata/Metadata.mdx index 2a797e2f..e6f18763 100644 --- a/src/components/Metadata/Metadata.mdx +++ b/src/components/Metadata/Metadata.mdx @@ -1,11 +1,13 @@ --- title: Project Metadata menu: Components +edit: false --- -import { Playground, Props } from 'docz'; +import { Props } from 'docz'; import Metadata from './Metadata'; -import DEMO_DATA from './Metadata.Demo'; +import { MetadataDemo } from './Metadata.demo'; +import DemoWrapper from '../docs/components/DemoWrapper/DemoWrapper'; # Project Metadata @@ -18,10 +20,6 @@ and also the ranges. The first section ends at 40s try to modify the currentTime to 45s. - - - + + + diff --git a/src/components/MetadataDisplay/MetadataDisplay.mdx b/src/components/MetadataDisplay/MetadataDisplay.mdx index 26ff574c..d86ed113 100644 --- a/src/components/MetadataDisplay/MetadataDisplay.mdx +++ b/src/components/MetadataDisplay/MetadataDisplay.mdx @@ -1,6 +1,7 @@ --- title: Metadata Display menu: Components +edit: false --- import { Playground, Props } from 'docz'; import MetadataDisplay from './MetadataDisplay'; diff --git a/src/components/MetadataEditor/MetadataEditor.mdx b/src/components/MetadataEditor/MetadataEditor.mdx index 9398a84e..0cc625c3 100644 --- a/src/components/MetadataEditor/MetadataEditor.mdx +++ b/src/components/MetadataEditor/MetadataEditor.mdx @@ -1,6 +1,7 @@ --- title: Metadata Editor menu: Components +edit: false --- import { Playground, Props } from 'docz'; import MetadataEditor from './MetadataEditor'; diff --git a/src/components/NextButton/NextButton.mdx b/src/components/NextButton/NextButton.mdx index 429b90cb..db9a9921 100644 --- a/src/components/NextButton/NextButton.mdx +++ b/src/components/NextButton/NextButton.mdx @@ -1,6 +1,7 @@ --- name: Next Button menu: Components +edit: false --- import { Playground, Props } from 'docz'; @@ -9,12 +10,12 @@ import NextButton from './NextButton'; # Next Button Component -## Next Button +## Next Button Demo {alert('Play button clicked.')}} /> -## Next Button Disabled State +## Next Button Disabled State Demo {alert('This shouldn\'t render.')}} /> diff --git a/src/components/PlayPauseButton/PlayPauseButton.mdx b/src/components/PlayPauseButton/PlayPauseButton.mdx index fa91c4b9..778a6e40 100644 --- a/src/components/PlayPauseButton/PlayPauseButton.mdx +++ b/src/components/PlayPauseButton/PlayPauseButton.mdx @@ -1,6 +1,7 @@ --- name: Play/Pause Button menu: Components +edit: false --- import { Playground, Props } from 'docz'; diff --git a/src/components/Playhead/Playhead.mdx b/src/components/Playhead/Playhead.mdx index 67ab2ed3..b02918aa 100644 --- a/src/components/Playhead/Playhead.mdx +++ b/src/components/Playhead/Playhead.mdx @@ -1,6 +1,7 @@ --- title: Playhead menu: Components +edit: false --- import { Props } from 'docz'; diff --git a/src/components/PreviousButton/PreviousButton.mdx b/src/components/PreviousButton/PreviousButton.mdx index 9bd91870..58755ffc 100644 --- a/src/components/PreviousButton/PreviousButton.mdx +++ b/src/components/PreviousButton/PreviousButton.mdx @@ -1,6 +1,7 @@ --- name: Previous Button menu: Components +edit: false --- import { Playground, Props } from 'docz'; diff --git a/src/components/PrimaryButton/PrimaryButton.mdx b/src/components/PrimaryButton/PrimaryButton.mdx index 1aaef50d..08ee15a6 100644 --- a/src/components/PrimaryButton/PrimaryButton.mdx +++ b/src/components/PrimaryButton/PrimaryButton.mdx @@ -1,16 +1,18 @@ --- title: Primary Button menu: Components +edit: false --- -import { Playground, Props } from 'docz'; +import { Props } from 'docz'; import PrimaryButton from './PrimaryButton'; +import DemoWrapper from '../docs/components/DemoWrapper/DemoWrapper'; # Primary Button Should be used as the current call to action. ## Primary Button - - Save - + + Save + diff --git a/src/components/ProjectMetadataDisplay/ProjectMetadataDisplay.mdx b/src/components/ProjectMetadataDisplay/ProjectMetadataDisplay.mdx index f83ea7d1..26025022 100644 --- a/src/components/ProjectMetadataDisplay/ProjectMetadataDisplay.mdx +++ b/src/components/ProjectMetadataDisplay/ProjectMetadataDisplay.mdx @@ -1,6 +1,7 @@ --- title: Project Metadata Display menu: Components +edit: false --- import { Playground, Props } from 'docz'; diff --git a/src/components/ProjectMetadataEditor/ProjectMetadataEditor.mdx b/src/components/ProjectMetadataEditor/ProjectMetadataEditor.mdx index e7ff2999..a6e31f57 100644 --- a/src/components/ProjectMetadataEditor/ProjectMetadataEditor.mdx +++ b/src/components/ProjectMetadataEditor/ProjectMetadataEditor.mdx @@ -1,6 +1,7 @@ --- title: Project Metadata Editor menu: Components +edit: false --- import { Playground, Props } from 'docz'; diff --git a/src/components/ReactSound/ReactSound.jsx b/src/components/ReactSound/ReactSound.jsx index c6e1baa0..755120a1 100644 --- a/src/components/ReactSound/ReactSound.jsx +++ b/src/components/ReactSound/ReactSound.jsx @@ -1,5 +1,6 @@ import React, { Component } from 'react'; import Sound from 'react-sound'; +import formatDate from 'date-fns/format'; const Scrubber = ({ duration, onScrub, position }) => { return ( diff --git a/src/components/ReactSound/ReactSound.mdx b/src/components/ReactSound/ReactSound.mdx index 6201ca4c..883d946e 100644 --- a/src/components/ReactSound/ReactSound.mdx +++ b/src/components/ReactSound/ReactSound.mdx @@ -1,6 +1,7 @@ --- title: React sound menu: Proof of concepts +edit: false --- # React sound proof of concept diff --git a/src/components/SettingsPopoup/SettingsPopup.demo.jsx b/src/components/SettingsPopoup/SettingsPopup.demo.jsx new file mode 100644 index 00000000..6f360029 --- /dev/null +++ b/src/components/SettingsPopoup/SettingsPopup.demo.jsx @@ -0,0 +1,29 @@ +import React, { useState } from 'react'; +import SettingsPopup from './SettingsPopup'; +import Button from '@material-ui/core/Button'; + +export const SettingsPopupDemo = () => { + const [isSettingsOpen, setIsSettingsOpen] = useState(false); + const [settingsJSON, setSettingsJSON] = useState(null); + return ( +
+ + setIsSettingsOpen(false)} + onSave={manifest => { + setIsSettingsOpen(false); + setSettingsJSON(JSON.stringify(manifest, null, 2)); + }} + /> + {settingsJSON && ( +
+ Manifest: +
{settingsJSON}
+
+ )} +
+ ); +}; diff --git a/src/components/SettingsPopoup/SettingsPopup.mdx b/src/components/SettingsPopoup/SettingsPopup.mdx index b4617e0b..16377558 100644 --- a/src/components/SettingsPopoup/SettingsPopup.mdx +++ b/src/components/SettingsPopoup/SettingsPopup.mdx @@ -1,11 +1,12 @@ --- title: Settings Popup menu: Components +edit: false --- -import { Playground, Props } from 'docz'; -import Component from '@reach/component-component'; +import { Props } from 'docz'; import SettingsPopup from './SettingsPopup'; -import Button from '@material-ui/core/Button'; +import { SettingsPopupDemo } from './SettingsPopup.demo'; +import DemoWrapper from '../docs/components/DemoWrapper/DemoWrapper'; # Settings Popup @@ -13,51 +14,6 @@ import Button from '@material-ui/core/Button'; ## Settings Popup Demo - - - - {({ setState, state }) => ( -
- - { - setState({ - isSettingsOpen:false, - }); - } - } - onSave={ - (manifest) => { - setState({ - isSettingsOpen:false, - settingsJSON: JSON.stringify(manifest, null, 2), - }); - } - } - /> - { - state.settingsJSON && ( -
- Manifest: -
-              {state.settingsJSON}
-            
-
- ) - } -
- )} -
-
+ + + diff --git a/src/components/SingleBubble/SingleBubble.mdx b/src/components/SingleBubble/SingleBubble.mdx index d26e7f3b..392e1373 100644 --- a/src/components/SingleBubble/SingleBubble.mdx +++ b/src/components/SingleBubble/SingleBubble.mdx @@ -1,11 +1,13 @@ --- title: Single Bubble menu: Components +edit: false --- import { Playground, Props } from 'docz'; import SingleBubble from './SingleBubble'; import { BUBBLE_STYLES } from '../../constants/project'; +import DemoWrapper from '../docs/components/DemoWrapper/DemoWrapper'; # Single Bubble Demo SVG React component that will render a single bubble shape when given a height, width and style. @@ -13,7 +15,7 @@ SVG React component that will render a single bubble shape when given a height, ## Single Bubble Demo - + - + diff --git a/src/components/SkipAheadButton/SkipAheadButton.mdx b/src/components/SkipAheadButton/SkipAheadButton.mdx index 7bd1ba13..58486399 100644 --- a/src/components/SkipAheadButton/SkipAheadButton.mdx +++ b/src/components/SkipAheadButton/SkipAheadButton.mdx @@ -1,6 +1,7 @@ --- name: Skip Ahead Button menu: Components +edit: false --- import { Playground, Props } from 'docz'; diff --git a/src/components/SkipBackwardsButton/SkipBackwardsButton.mdx b/src/components/SkipBackwardsButton/SkipBackwardsButton.mdx index 88882679..75e6b6d6 100644 --- a/src/components/SkipBackwardsButton/SkipBackwardsButton.mdx +++ b/src/components/SkipBackwardsButton/SkipBackwardsButton.mdx @@ -1,6 +1,7 @@ --- name: Skip Backwards Button menu: Components +edit: false --- import { Playground, Props } from 'docz'; diff --git a/src/components/TimePicker/TimePicker.demo.jsx b/src/components/TimePicker/TimePicker.demo.jsx new file mode 100644 index 00000000..9ad6e3cc --- /dev/null +++ b/src/components/TimePicker/TimePicker.demo.jsx @@ -0,0 +1,30 @@ +import React, { useState } from 'react'; +import TimePicker from './TimePicker'; + +export const TimePickerDemo = () => { + const [currentTime, setCurrentTime] = useState(1 * 60 * 1000); + return ( +
+ setCurrentTime(value)} + /> + {currentTime} +
+ ); +}; + +export const TimePickerDemoWithRange = () => { + const [currentTime, setCurrentTime] = useState(2 * 60 * 1000); + return ( +
+ setCurrentTime(value)} + min={2 * 60 * 1000} + max={60 * 60 * 1000} + /> + {currentTime} +
+ ); +}; diff --git a/src/components/TimePicker/TimePicker.mdx b/src/components/TimePicker/TimePicker.mdx index 7f1e3152..ad140525 100644 --- a/src/components/TimePicker/TimePicker.mdx +++ b/src/components/TimePicker/TimePicker.mdx @@ -1,29 +1,24 @@ --- -title: Time Picker +title: Time Picker menu: Components +edit: false --- -import { Playground, Props } from 'docz'; -import Component from "@reach/component-component"; -import TimePicker from './TimePicker'; +import { Props } from 'docz'; +import TimePicker from './TimePicker'; +import { TimePickerDemo, TimePickerDemoWithRange } from './TimePicker.demo'; +import DemoWrapper from '../docs/components/DemoWrapper/DemoWrapper'; # Time Picker +## Time Picker Demo + + + - - - {({ setState, state }) => ( -
- setState({currentTime: ev.target.value})} - min={2*60*1000} - max={4.5*60*1000} - /> - {state.currentTime} -
- )} -
-
+## Time Picker Demo with Range (max = 1 hour, min = 2 minutes) + + + diff --git a/src/components/TimelineMarker/TimelineMarker.mdx b/src/components/TimelineMarker/TimelineMarker.mdx index 25393eb7..2c700243 100644 --- a/src/components/TimelineMarker/TimelineMarker.mdx +++ b/src/components/TimelineMarker/TimelineMarker.mdx @@ -1,6 +1,7 @@ --- title: Timeline marker menu: Components +edit: false --- import { Playground, Props } from 'docz'; @@ -9,9 +10,9 @@ import TimelineMarker from './TimelineMarker'; # Timeline marker Icon for displaying a marker on the timeline. - + - + diff --git a/src/components/TimelineScrubber/TimelineScrubber.demo.jsx b/src/components/TimelineScrubber/TimelineScrubber.demo.jsx new file mode 100644 index 00000000..09d8bf3f --- /dev/null +++ b/src/components/TimelineScrubber/TimelineScrubber.demo.jsx @@ -0,0 +1,83 @@ +import React, { useState } from 'react'; +import TimelineScrubber from './TimelineScrubber'; +import BubbleDisplay from '../BubbleDisplay/BubbleDisplay'; +import SingleBubble from '../SingleBubble/SingleBubble'; +import { colourPalettes } from '../../config'; + +const POINTS = { + 'id-1': { + id: 'id-1', + startTime: 0, + endTime: 1000, + depth: 2, + label: 'Composition', + summary: 'some summary', + isSelected: false, + colour: '#C797F0', + }, + 'id-2': { + id: 'id-2', + startTime: 0, + endTime: 400, + depth: 1, + label: 'Part I', + summary: 'some summary', + isSelected: false, + colour: '#A8F097', + }, + 'id-3': { + id: 'id-3', + startTime: 400, + endTime: 1000, + depth: 1, + label: 'Part II', + summary: 'some summary', + isSelected: false, + colour: '#A8F097', + }, +}; + +const noop = () => { }; + +const timePoints = Array.from( + Object.values(POINTS).reduce((_timePoints, bubble) => { + _timePoints.add(bubble.startTime); + _timePoints.add(bubble.endTime); + return _timePoints; + }, new Set()) +); + +const runTime = Math.max.apply(null, timePoints); + +export const TimelineScrubberWithBubblesDemo = () => { + const [currentTime, setCurrentTime] = useState(0); + const editorWidth = 700; + + return ( +
+ + {pts => + pts.map(bubble => ( + + )) + } + + +
+ ); +}; diff --git a/src/components/TimelineScrubber/TimelineScrubber.jsx b/src/components/TimelineScrubber/TimelineScrubber.jsx index ca5e2066..7e8b0f10 100644 --- a/src/components/TimelineScrubber/TimelineScrubber.jsx +++ b/src/components/TimelineScrubber/TimelineScrubber.jsx @@ -61,7 +61,7 @@ class TimelineScrubber extends Component { }; static defaultProps = { - onUpdateTime: () => {}, + onUpdateTime: () => { }, onUpdatePoint: null, // This changes behaviour depending if null. onUpdateTimePoint: null, // This changes behaviour depending if null. timePoints: [], @@ -69,6 +69,10 @@ class TimelineScrubber extends Component { showTimes: false, isPlayheadUpdating: false, playheadX: 0, + markers: {}, + x: 0, + width: 0, + dragStart: () => () => { }, }; state = { isHovering: false, hoverTime: 0 }; @@ -107,8 +111,8 @@ class TimelineScrubber extends Component { timePointIndex === 0 ? 'translate(0)' : timePointIndex === timePoints.length - 1 - ? 'translate(-100%)' - : 'translate(-50%)', + ? 'translate(-100%)' + : 'translate(-50%)', }); handleAddPoint = ev => { @@ -131,7 +135,7 @@ class TimelineScrubber extends Component { const pos = getPalletXPosition( 80, - e.clientX + this.props.x, + e.clientX - bounds.left, bounds.width, 5 ); diff --git a/src/components/TimelineScrubber/TimelineScrubber.mdx b/src/components/TimelineScrubber/TimelineScrubber.mdx index 2593026a..777d2688 100644 --- a/src/components/TimelineScrubber/TimelineScrubber.mdx +++ b/src/components/TimelineScrubber/TimelineScrubber.mdx @@ -1,64 +1,29 @@ --- title: Timeline scrubber menu: Components +edit: false --- -import { Playground, Props } from 'docz'; -import Component from '@reach/component-component'; +import { Props } from 'docz'; import TimelineScrubber from './TimelineScrubber'; -import DEMO_POINTS from '../BubbleDisplay/BubbleDisplay.DemoPoints'; -import BubbleDisplay from '../BubbleDisplay/BubbleDisplay'; -import SingleBubble from '../SingleBubble/SingleBubble'; +import { TimelineScrubberWithBubblesDemo } from './TimelineScrubber.demo'; +import DemoWrapper from '../docs/components/DemoWrapper/DemoWrapper'; # Timeline scrubber Interactions with the timeline, dragging and clicking to add points. -# Simple Scrubber Demo - +## Simple Scrubber Demo + - + ## Scrubber with Bubbles Demo - - - {({ setState, state }) => { - const timePoints = Array.from(Object.values(state.points).reduce((_timePoints, bubble) => { - _timePoints.add(bubble.startTime); - _timePoints.add(bubble.endTime); - return _timePoints; - }, new Set())); - return ( -
- - {points=>points.map(bubble => )} - - -
- ); - }} -
-
+ + + diff --git a/src/components/TransportBarButton/TransportBarButton.mdx b/src/components/TransportBarButton/TransportBarButton.mdx index cc4a2470..72b19403 100644 --- a/src/components/TransportBarButton/TransportBarButton.mdx +++ b/src/components/TransportBarButton/TransportBarButton.mdx @@ -1,48 +1,50 @@ --- name: Transport Bar Button menu: Components +edit: false --- -import { Playground, Props } from 'docz'; +import { Props } from 'docz'; import TransportBarButton from './TransportBarButton'; import PlayCircleFilled from '@material-ui/icons/PlayCircleFilled'; +import DemoWrapper from '../docs/components/DemoWrapper/DemoWrapper'; # Transport Bar Button component ## Transport Bar Button with SVG Icon - - {alert('Play button clicked.')}}> - - - - - - - + + {alert('Play button clicked.')}}> + + + + + + + ## Transport Bar Button with Material Icon - - {alert('Play button clicked.')}}> - - - + + {alert('Play button clicked.')}}> + + + ## Disabled Transport Bar Button - - {alert('This shouldn\'t render.')}}> - - - + + {alert('This shouldn\'t render.')}}> + + + diff --git a/src/components/VariationsAppBar/VariationsAppBar.demo.jsx b/src/components/VariationsAppBar/VariationsAppBar.demo.jsx new file mode 100644 index 00000000..5e829bbf --- /dev/null +++ b/src/components/VariationsAppBar/VariationsAppBar.demo.jsx @@ -0,0 +1,16 @@ +import React from 'react'; +import VariationsAppBar from './VariationsAppBar'; + +const noop = () => {}; + +export const VariationsAppBarDemo = () => { + return ( + + ); +}; diff --git a/src/components/VariationsAppBar/VariationsAppBar.mdx b/src/components/VariationsAppBar/VariationsAppBar.mdx index 1230362d..6f2f3680 100644 --- a/src/components/VariationsAppBar/VariationsAppBar.mdx +++ b/src/components/VariationsAppBar/VariationsAppBar.mdx @@ -1,20 +1,18 @@ --- -title: App Bar +title: App Bar menu: Components +edit: false --- -import { Playground, Props } from 'docz'; -import Component from "@reach/component-component"; +import { Props } from 'docz'; import VariationsAppBar from './VariationsAppBar'; +import { VariationsAppBarDemo } from './VariationsAppBar.demo'; +import DemoWrapper from '../docs/components/DemoWrapper/DemoWrapper'; - +# Variations App Bar component - - - - {({ setState, state }) => ( - setState({title})}/> - )} - - +## Variations App Bar Demo + + + diff --git a/src/components/VerifyDialog/VerifyDialog.demo.jsx b/src/components/VerifyDialog/VerifyDialog.demo.jsx new file mode 100644 index 00000000..5cdeeae7 --- /dev/null +++ b/src/components/VerifyDialog/VerifyDialog.demo.jsx @@ -0,0 +1,21 @@ +import React, { useState } from 'react'; +import VerifyDialog from './VerifyDialog'; +import Button from '@material-ui/core/Button'; + +export const VerifyDialogDemo = () => { + const [open, setOpen] = useState(false); + return ( +
+ + setOpen(false)} + onProceed={() => setOpen(false)} + /> +
+ ); +}; diff --git a/src/components/VerifyDialog/VerifyDialog.mdx b/src/components/VerifyDialog/VerifyDialog.mdx index e66e782a..0689f550 100644 --- a/src/components/VerifyDialog/VerifyDialog.mdx +++ b/src/components/VerifyDialog/VerifyDialog.mdx @@ -1,29 +1,18 @@ --- -title: Verify Dialog +title: Verify Dialog menu: Components +edit: false --- -import { Playground, Props } from 'docz'; -import Component from "@reach/component-component"; +import { Props } from 'docz'; import VerifyDialog from './VerifyDialog'; +import { VerifyDialogDemo } from './VerifyDialog.demo'; +import DemoWrapper from '../docs/components/DemoWrapper/DemoWrapper'; - +# Verify Dialog component - - - - {({ setState, state }) => ( -
- - setState({open:false})} onProceed={()=>setState({open:false})}/> -
- )} -
-
+## Verify Dialog Demo + + + diff --git a/src/components/VolumeSlider/VolumeSlider.demo.jsx b/src/components/VolumeSlider/VolumeSlider.demo.jsx new file mode 100644 index 00000000..e4c1dfce --- /dev/null +++ b/src/components/VolumeSlider/VolumeSlider.demo.jsx @@ -0,0 +1,12 @@ +import React, { useState } from 'react'; +import VolumeSlider from './VolumeSlider'; + +export const VolumeSliderDemo = () => { + const [volume, setVolume] = useState(70); + return ( + + ); +}; diff --git a/src/components/VolumeSlider/VolumeSlider.jsx b/src/components/VolumeSlider/VolumeSlider.jsx index 05b998af..15e23372 100644 --- a/src/components/VolumeSlider/VolumeSlider.jsx +++ b/src/components/VolumeSlider/VolumeSlider.jsx @@ -12,7 +12,7 @@ const SPEAKER_ICON_SIZE = { }; function VolumeSlider({ volume, onVolumeChanged }) { - const { containerRef, onVolumeInputChange } = useVolumeSlider(volume, onVolumeChanged); + const { containerRef, onVolumeInputChange, onKeyDown } = useVolumeSlider(volume, onVolumeChanged); return (
)} @@ -231,6 +236,7 @@ class BubbleEditor extends React.Component { } const mapStateProps = state => ({ + isModalOpen: state.viewState[VIEWSTATE.IS_IMPORT_OPEN] || state.viewState[VIEWSTATE.IS_SETTINGS_OPEN], currentTime: state.viewState[VIEWSTATE.CURRENT_TIME], runTime: state.viewState[VIEWSTATE.RUNTIME], markers: state.markers.visible ? state.markers.list : {}, @@ -262,6 +268,49 @@ const mapDispatchToProps = { updateViewerWidth, }; +BubbleEditor.propTypes = { + // From Redux state + isModalOpen: PropTypes.bool, + currentTime: PropTypes.number, + runTime: PropTypes.number, + markers: PropTypes.object, + points: PropTypes.object, + selectedPoints: PropTypes.arrayOf(PropTypes.string), + zoom: PropTypes.number, + x: PropTypes.number, + viewerWidth: PropTypes.number, + bubbleHeight: PropTypes.number, + bubbleStyle: PropTypes.string, + showTimes: PropTypes.bool, + blackAndWhiteMode: PropTypes.bool, + backgroundColour: PropTypes.string, + colourPalette: PropTypes.object, + // From Redux dispatch + onUpdateTime: PropTypes.func, + splitRange: PropTypes.func, + selectRange: PropTypes.func, + deselectRange: PropTypes.func, + updateViewerWidth: PropTypes.func, + // From pan HOC + onPanStart: PropTypes.func, + viewport: PropTypes.shape({ + startX: PropTypes.number, + x: PropTypes.number, + }), + // From dragBubbleMarker HOC + bubbleMarkerMovement: PropTypes.object, + dragStartBubbleMarker: PropTypes.func, + // From dragPlayhead HOC + playhead: PropTypes.shape({ + isUpdating: PropTypes.bool, + x: PropTypes.number, + }), + dragStartPlayhead: PropTypes.func, + // From dragMarker HOC + markerMovement: PropTypes.object, + dragStartMarker: PropTypes.func, +}; + export default compose( pan, dragBubbleMarker, diff --git a/src/containers/BubbleEditor/BubbleEditor.mdx b/src/containers/BubbleEditor/BubbleEditor.mdx index 0384fd1b..b4407c03 100644 --- a/src/containers/BubbleEditor/BubbleEditor.mdx +++ b/src/containers/BubbleEditor/BubbleEditor.mdx @@ -1,25 +1,25 @@ --- title: Bubble Editor menu: Containers +edit: false --- -# Bubble Editor view - -The bubble editor is a composite view. It glues together -the Timeline and Bubble displays with stores and actions required -to create the experience. - - -import { Playground, Props } from 'docz'; +import { Props } from 'docz'; import { Provider } from 'react-redux'; import configureStore from '../../store/main'; -import rootReducer from '../../reducers/root'; -import BubbleEditor from './BubbleEditor'; +import BubbleEditor, { BubbleEditor as BubbleEditorClass } from './BubbleEditor'; +import DemoWrapper from '../../components/docs/components/DemoWrapper/DemoWrapper'; + +# Bubble Editor view - +The bubble editor is a composite view. It glues together +the Timeline and Bubble displays with stores and actions required +to create the experience. + - - +## Bubble Editor Demo + + - + diff --git a/src/containers/Root/Root.jsx b/src/containers/Root/Root.jsx index 39ed8ce2..d49e8d2b 100644 --- a/src/containers/Root/Root.jsx +++ b/src/containers/Root/Root.jsx @@ -36,6 +36,13 @@ const Root = ({ Root.propTypes = { store: PropTypes.object.isRequired, + persistor: PropTypes.object.isRequired, + callback: PropTypes.func, + hasResource: PropTypes.bool, + noFooter: PropTypes.bool, + noHeader: PropTypes.bool, + noVideo: PropTypes.bool, + noSourceLink: PropTypes.bool, }; export default Root; diff --git a/src/containers/Root/Root.mdx b/src/containers/Root/Root.mdx index f8ac50a2..1e3073bd 100644 --- a/src/containers/Root/Root.mdx +++ b/src/containers/Root/Root.mdx @@ -1,8 +1,13 @@ --- title: Root Container menu: Containers +edit: false --- +import { Props } from 'docz'; +import Root from './Root'; + # Root Container The root container provides the redux store for the application. + diff --git a/src/components/Metadata/Metadata.Demo.js b/src/containers/VariationsMainView/Metadata.Demo.js similarity index 100% rename from src/components/Metadata/Metadata.Demo.js rename to src/containers/VariationsMainView/Metadata.Demo.js diff --git a/src/containers/VariationsMainView/VariationsMainView.jsx b/src/containers/VariationsMainView/VariationsMainView.jsx index 59e16dbe..ce25218e 100644 --- a/src/containers/VariationsMainView/VariationsMainView.jsx +++ b/src/containers/VariationsMainView/VariationsMainView.jsx @@ -114,7 +114,7 @@ class VariationsMainView extends React.Component { addRange = selected => () => { this.props.splitRangeAt( (selected[RANGE.END_TIME] - selected[RANGE.START_TIME]) / 2 + - selected[RANGE.START_TIME] + selected[RANGE.START_TIME] ); }; @@ -233,10 +233,10 @@ class VariationsMainView extends React.Component { onRedo={this.props.onRedo} onUndo={this.props.onUndo} onSave={this.getOnSave()} - onTitleChange={() => {}} + onTitleChange={() => { }} hasResource={this.props.hasResource} noHeader={this.props.noHeader} - isModalOpen={this.props.isImportOpen || this.props.isSettingsOpen} + isModalOpen={this.props.isImportOpen || this.props.isSettingsOpen} />
- {this.props.url ? ( + key={'bubble--' + this.props.url} + isModalOpen={this.props.isImportOpen || this.props.isSettingsOpen} + /> + {/* + Render Audio player ONLY when the content is not being played as video. + i.e., either the Manifest is not video, or video playback is opted out via 'noVideo' prop. + */} + {this.props.url && !(this.props.isVideo && !this.props.noVideo) ? (
@@ -326,7 +330,7 @@ class VariationsMainView extends React.Component { // Enable Video playback in the timeliner isVideo={!noVideo && this.props.isVideo} poster={this.props.poster} - isModalOpen={this.props.isImportOpen || this.props.isSettingsOpen} + isModalOpen={this.props.isImportOpen || this.props.isSettingsOpen} /> {!noFooter &&
}
diff --git a/src/containers/VariationsMainView/VariationsMainView.mdx b/src/containers/VariationsMainView/VariationsMainView.mdx index c20fc769..914b2ca7 100644 --- a/src/containers/VariationsMainView/VariationsMainView.mdx +++ b/src/containers/VariationsMainView/VariationsMainView.mdx @@ -1,23 +1,23 @@ --- title: Variations Main View menu: Containers +edit: false --- # Variations Main View The main application view -import { Playground, Props } from 'docz'; -import VariationsMainView from './VariationsMainView'; +import { Props } from 'docz'; import { Provider } from 'react-redux'; -import DEMO_POINTS from '../../components/Metadata/Metadata.Demo'; import configureStore from '../../store/main'; -import rootReducer from '../../reducers/root'; +import VariationsMainView from './VariationsMainView'; +import DemoWrapper from '../../components/docs/components/DemoWrapper/DemoWrapper'; - - - + + + - + diff --git a/src/containers/Video/Video.Demo.jsx b/src/containers/Video/Video.demo.jsx similarity index 81% rename from src/containers/Video/Video.Demo.jsx rename to src/containers/Video/Video.demo.jsx index 51b7723a..6a5eb98f 100644 --- a/src/containers/Video/Video.Demo.jsx +++ b/src/containers/Video/Video.demo.jsx @@ -4,14 +4,6 @@ import Video from './Video'; import { play, pause } from '../../actions/viewState'; class VideoDemo extends Component { - play = () => { - this.props.play(); - }; - - pause = () => { - this.props.pause(); - }; - render() { const { loadingPercent, currentTime, runTime, isPlaying } = this.props; return ( @@ -21,9 +13,9 @@ class VideoDemo extends Component { {loadingPercent !== 100 ? ( '' ) : isPlaying ? ( - + ) : ( - + )}
Loaded {loadingPercent}% - {currentTime} / {runTime} diff --git a/src/containers/Video/Video.jsx b/src/containers/Video/Video.jsx index a00c3426..5c0a63a9 100644 --- a/src/containers/Video/Video.jsx +++ b/src/containers/Video/Video.jsx @@ -1,50 +1,32 @@ import React, { useLayoutEffect, useRef, useState } from 'react'; +import PropTypes from 'prop-types'; import { connect } from 'react-redux'; -import { seek, play, pause, setVolume } from '../../actions/viewState'; +import { mediaLoading, mediaLoaded, mediaError } from '../../actions/canvas'; +import { setCurrentTime, finishedPlaying, seek, play, pause, setVolume } from '../../actions/viewState'; import Button from '@material-ui/core/Button'; import PictureInPicture from '@material-ui/icons/PictureInPicture'; -// Media Element -import 'mediaelement/standalone'; import useEventListener from '../../hooks/useEventListener'; +import useMediaPlayer from '../../hooks/useMediaPlayer'; -const { MediaElement } = window; - -function Video({ url, volume, currentTime, startTime, isPlaying, poster, isSeeked, ...props }) { +function VideoPlayer({ url, volume, poster, ...props }) { const video = useRef(); - const player = useRef(); - const sources = [{ src: url }]; - const lastTime = useRef(() => startTime - 1); const lastVolume = useRef(); const [pipButtonText, setPipButtonText] = useState('Enter Picture-in-Picture mode'); + const player = useMediaPlayer(video, { url, volume, ...props }); + // Styling for video and PIP button const videoStyle = { background: 'black', boxShadow: 'gray 2px 2px 4px' }; const videoDivStyle = { margin: '0 auto', padding: '5px' }; const pipButtonStyles = { display: 'none', alignItems: 'center', flexWrap: 'wrap', marginTop: '20px' }; - useLayoutEffect(() => { - const element = new MediaElement( - video.current, - { - currentTime: currentTime / 1000, - }, - sources - ); - player.current = element; - // Set volume to zero, use audio player's volume - player.current.setVolume(0); - - return () => { - element.remove(); - }; - }, []); - - // When Picture-in-Picture is not an in-built feature of the browser, - // use an external button to use the Picture-in-Picture Web API - // to enable the feature - // Reference: https://css-tricks.com/an-introduction-to-the-picture-in-picture-web-api/ + /** + * When Picture-in-Picture is not an in-built feature of the browser, + * create an external button to provide the Picture-in-Picture feature via Web API. + * Reference: https://css-tricks.com/an-introduction-to-the-picture-in-picture-web-api/ + */ const initPIP = () => { const pipButton = document.getElementById('timeliner-pip-button'); const videoElement = document.getElementsByTagName('video')[0]; @@ -78,36 +60,21 @@ function Video({ url, volume, currentTime, startTime, isPlaying, poster, isSeeke }); }; - // Re-create player instance with media swap - // TODO:: There's a slight time difference in the video and audio - // players when media file gets swapped. - // To reproduce: load a manifest -> play media -> pause media - // -> swap media file with 'Open audio file' in toolbar -> - // play media -> observe currentTime diff in the audio and video players - useLayoutEffect(() => { - if (url != null && player.current == null) { - player.current = new MediaElement( - video.current, - { - currentTime: currentTime / 1000, - }, - [{ src: url }] - ); - player.current.setVolume(0); - player.current.setCurrentTime(currentTime / 1000); - }; - }, [url]); - - // Store last non-zero volume to restore it - // when using PiP controls + // Store last non-zero volume to restore it when using PiP controls useLayoutEffect(() => { if (volume > 0) { lastVolume.current = volume; } }, [volume]); - // Propagate play/pause and mute/unmute events from the picture-in-picture - // player window to audio player + /** + * Handle user interactions with the controls in the Picture-in-Picture window. + * These event handlers propagate, + * - play/pause + * - mute/unmute or volume change + * events to the state by calling relevant Redux actions to update the controls in the + * controls bar in the main window accordingly. + */ useEventListener(player, 'play', () => { props.play(); }, [url]); @@ -120,46 +87,16 @@ function Video({ url, volume, currentTime, startTime, isPlaying, poster, isSeeke } else { props.setVolume(lastVolume.current); } - }, [volume, url]); + }, [url]); + + /** + * Initialize the Picture-in-Picture buttton when the video's metadata is loaded for browsers, + * that do not have native support for it. + */ useEventListener(player, 'loadedmetadata', () => { initPIP(); }); - // Handle play/pause events from the audio player - useLayoutEffect(() => { - if (player.current) { - if (isPlaying) { - player.current.setCurrentTime(currentTime / 1000); - player.current.play(); - lastTime.current = player.current.currentTime; - } else { - if (player.current.readyState) { - player.current.pause(); - } - } - } - }, [isPlaying, url]); - - // While the video player is always on mute, sync mute/unmute - // in the picture-in-picture window for visual purposes - useLayoutEffect(() => { - if (player.current && volume == 0) { - player.current.setMuted(true); - } else { - player.current.setMuted(false); - } - }, [volume, url]); - - // Handle current time when seeked. - useLayoutEffect(() => { - if (player.current) { - lastTime.current = currentTime; - player.current.setCurrentTime(currentTime / 1000); - } - // Reset isSeeked state variable - props.seek(false); - }, [isSeeked, url]); - if (!url) { return null; } @@ -169,7 +106,10 @@ function Video({ url, volume, currentTime, startTime, isPlaying, poster, isSeeke