From 9232f4d52ef192fe7464aca8790c12d406845c42 Mon Sep 17 00:00:00 2001 From: Ollie Taylor <13766232+OllieJT@users.noreply.github.com> Date: Mon, 6 Mar 2023 15:25:34 +0000 Subject: [PATCH] Podcast player components (#37) --- .changeset/strange-dolls-burn.md | 12 + .eslintignore | 2 + .eslintrc.cjs | 3 + .gitignore | 1 + .prettierrc | 3 + .vscode/extensions.json | 1 + .vscode/settings.json | 5 +- package.json | 38 +-- pnpm-lock.yaml | 148 +++++---- src/app.d.ts | 1 + src/app.html | 7 +- src/lib/audio/audio-element.ts | 4 +- src/lib/audio/audio-loader.svelte | 99 +++++- src/lib/audio/episode-data.ts | 10 +- src/lib/audio/episode-details.ts | 2 +- src/lib/audio/episode-progress.ts | 6 +- src/lib/audio/index.ts | 8 +- src/lib/components/audio-progress.svelte | 21 -- src/lib/components/headless-timeline.svelte | 145 +++++++++ src/lib/components/index.ts | 3 + src/lib/components/player-stack.svelte | 318 ++++++++++++++++++++ src/lib/components/player-widget.svelte | 234 ++++++++++++++ src/lib/components/utility/a11y-icon.svelte | 9 + src/lib/components/utility/index.ts | 4 + src/lib/components/utility/skip.svelte | 155 ++++++++++ src/lib/components/utility/spinner.svelte | 62 ++++ src/lib/components/utility/timestamp.svelte | 19 ++ src/lib/index.ts | 7 +- src/lib/user/preferences.ts | 2 +- src/lib/user/progress.ts | 8 +- src/lib/utility/index.ts | 1 + src/lib/utility/package/log.ts | 8 +- src/lib/utility/seconds-to-timestamp.ts | 4 +- src/routes/+layout.svelte | 2 +- src/routes/+page.svelte | 72 ++++- src/routes/another-page/+page.svelte | 104 ++++++- svelte.config.js | 3 +- 37 files changed, 1375 insertions(+), 156 deletions(-) create mode 100644 .changeset/strange-dolls-burn.md delete mode 100644 src/lib/components/audio-progress.svelte create mode 100644 src/lib/components/headless-timeline.svelte create mode 100644 src/lib/components/index.ts create mode 100644 src/lib/components/player-stack.svelte create mode 100644 src/lib/components/player-widget.svelte create mode 100644 src/lib/components/utility/a11y-icon.svelte create mode 100644 src/lib/components/utility/index.ts create mode 100644 src/lib/components/utility/skip.svelte create mode 100644 src/lib/components/utility/spinner.svelte create mode 100644 src/lib/components/utility/timestamp.svelte diff --git a/.changeset/strange-dolls-burn.md b/.changeset/strange-dolls-burn.md new file mode 100644 index 0000000..6ef213c --- /dev/null +++ b/.changeset/strange-dolls-burn.md @@ -0,0 +1,12 @@ +--- +'svelte-podcast': minor +--- + +Improves theming with css variables +Improves developer logs +Fixes various package export issues +Adds player components: + +- Player: `` +- Player: `` +- Utility: `` diff --git a/.eslintignore b/.eslintignore index 1d4b507..83c0f24 100644 --- a/.eslintignore +++ b/.eslintignore @@ -12,3 +12,5 @@ node_modules pnpm-lock.yaml package-lock.json yarn.lock + +**/components/_* \ No newline at end of file diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 68be379..11273fe 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -17,4 +17,7 @@ module.exports = { es2017: true, node: true, }, + rules: { + 'no-restricted-imports': ['error', { patterns: ['$lib', '$lib/*'] }], + }, }; diff --git a/.gitignore b/.gitignore index ac7211b..06a427b 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ node_modules !.env.example vite.config.js.timestamp-* vite.config.ts.timestamp-* +.eslintcache \ No newline at end of file diff --git a/.prettierrc b/.prettierrc index 89793ac..adc6cbc 100644 --- a/.prettierrc +++ b/.prettierrc @@ -4,6 +4,9 @@ "trailingComma": "all", "printWidth": 100, "plugins": ["prettier-plugin-svelte"], + "svelteSortOrder": "options-scripts-styles-markup", + "svelteBracketNewLine": true, + "svelteIndentScriptAndStyle": true, "pluginSearchDirs": ["."], "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] } diff --git a/.vscode/extensions.json b/.vscode/extensions.json index d9f6c4c..3687565 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -2,6 +2,7 @@ // See http://go.microsoft.com/fwlink/?LinkId=827846 // for the documentation about the extensions.json format "recommendations": [ + "dbaeumer.vscode-eslint", "aaron-bond.better-comments", "esbenp.prettier-vscode", "gruntfuggly.todo-tree" diff --git a/.vscode/settings.json b/.vscode/settings.json index fdce47e..e18140a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -7,6 +7,7 @@ "source.organizeImports": true }, "eslint.packageManager": "pnpm", + "eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact", "svelte"], "files.exclude": { "**/.DS_Store": true, "**/*-lock.*": true, @@ -21,5 +22,7 @@ "**/.svelte-kit": true }, "problems.sortOrder": "severity", - "todo-tree.tree.scanMode": "workspace only" + "todo-tree.tree.scanMode": "workspace only", + "javascript.preferences.importModuleSpecifier": "relative", + "typescript.preferences.importModuleSpecifier": "relative" } diff --git a/package.json b/package.json index 8c36b29..e882cb8 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,9 @@ "test": "playwright test", "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", - "lint": "prettier --check --plugin-search-dir=. .", + "lint:prettier": "prettier --check --plugin-search-dir=. .", + "lint:eslint": "TIMING=1 eslint . --ext .ts,.tsx,.svelte --cache", + "lint": "pnpm lint:prettier && pnpm lint:eslint", "format": "prettier --write --plugin-search-dir=. .", "release": "pnpm package && changeset publish", "ts": "tsc --pretty --noImplicitAny --noEmit" @@ -34,31 +36,33 @@ "dist" ], "peerDependencies": { - "svelte": "^3.54.0" + "svelte": "^3.55.1" }, "dependencies": { + "@inqling/svelte-icons": "^3.0.2", + "clsx": "^1.2.1", "just-clamp": "^4.2.0", "svelte-local-storage-store": "^0.4.0" }, "devDependencies": { "@changesets/cli": "^2.26.0", - "@playwright/test": "^1.28.1", + "@playwright/test": "^1.31.2", "@sveltejs/adapter-auto": "^2.0.0", - "@sveltejs/kit": "^1.5.0", - "@sveltejs/package": "^2.0.0", - "@typescript-eslint/eslint-plugin": "^5.45.0", - "@typescript-eslint/parser": "^5.45.0", - "eslint": "^8.28.0", - "eslint-config-prettier": "^8.5.0", + "@sveltejs/kit": "^1.10.0", + "@sveltejs/package": "^2.0.2", + "@typescript-eslint/eslint-plugin": "^5.54.0", + "@typescript-eslint/parser": "^5.54.0", + "eslint": "^8.35.0", + "eslint-config-prettier": "^8.6.0", "eslint-plugin-svelte3": "^4.0.0", - "prettier": "^2.8.0", - "prettier-plugin-svelte": "^2.8.1", - "publint": "^0.1.9", - "svelte": "^3.54.0", - "svelte-check": "^3.0.1", - "tslib": "^2.4.1", - "typescript": "^4.9.3", - "vite": "^4.0.0" + "prettier": "^2.8.4", + "prettier-plugin-svelte": "^2.9.0", + "publint": "^0.1.10", + "svelte": "^3.55.1", + "svelte-check": "^3.0.4", + "tslib": "^2.5.0", + "typescript": "^4.9.5", + "vite": "^4.1.4" }, "svelte": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e54d918..a9ca4ca 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2,44 +2,48 @@ lockfileVersion: 5.4 specifiers: '@changesets/cli': ^2.26.0 - '@playwright/test': ^1.28.1 + '@inqling/svelte-icons': ^3.0.2 + '@playwright/test': ^1.31.2 '@sveltejs/adapter-auto': ^2.0.0 - '@sveltejs/kit': ^1.5.0 - '@sveltejs/package': ^2.0.0 - '@typescript-eslint/eslint-plugin': ^5.45.0 - '@typescript-eslint/parser': ^5.45.0 - eslint: ^8.28.0 - eslint-config-prettier: ^8.5.0 + '@sveltejs/kit': ^1.10.0 + '@sveltejs/package': ^2.0.2 + '@typescript-eslint/eslint-plugin': ^5.54.0 + '@typescript-eslint/parser': ^5.54.0 + clsx: ^1.2.1 + eslint: ^8.35.0 + eslint-config-prettier: ^8.6.0 eslint-plugin-svelte3: ^4.0.0 just-clamp: ^4.2.0 - prettier: ^2.8.0 - prettier-plugin-svelte: ^2.8.1 - publint: ^0.1.9 - svelte: ^3.54.0 - svelte-check: ^3.0.1 + prettier: ^2.8.4 + prettier-plugin-svelte: ^2.9.0 + publint: ^0.1.10 + svelte: ^3.55.1 + svelte-check: ^3.0.4 svelte-local-storage-store: ^0.4.0 - tslib: ^2.4.1 - typescript: ^4.9.3 - vite: ^4.0.0 + tslib: ^2.5.0 + typescript: ^4.9.5 + vite: ^4.1.4 dependencies: + '@inqling/svelte-icons': 3.0.2_svelte@3.55.1 + clsx: 1.2.1 just-clamp: 4.2.0 svelte-local-storage-store: 0.4.0_svelte@3.55.1 devDependencies: '@changesets/cli': 2.26.0 - '@playwright/test': 1.31.1 - '@sveltejs/adapter-auto': 2.0.0_@sveltejs+kit@1.8.5 - '@sveltejs/kit': 1.8.5_svelte@3.55.1+vite@4.1.4 + '@playwright/test': 1.31.2 + '@sveltejs/adapter-auto': 2.0.0_@sveltejs+kit@1.10.0 + '@sveltejs/kit': 1.10.0_svelte@3.55.1+vite@4.1.4 '@sveltejs/package': 2.0.2_4x7phaipmicbaooxtnresslofa - '@typescript-eslint/eslint-plugin': 5.53.0_cjo54hduev4bqhpjw5znwiokqu - '@typescript-eslint/parser': 5.53.0_ycpbpc6yetojsgtrx3mwntkhsu + '@typescript-eslint/eslint-plugin': 5.54.0_6mj2wypvdnknez7kws2nfdgupi + '@typescript-eslint/parser': 5.54.0_ycpbpc6yetojsgtrx3mwntkhsu eslint: 8.35.0 eslint-config-prettier: 8.6.0_eslint@8.35.0 eslint-plugin-svelte3: 4.0.0_n4ieifq2d7jq3sqoe474cgqlim prettier: 2.8.4 prettier-plugin-svelte: 2.9.0_jrsxveqmsx2uadbqiuq74wlc4u - publint: 0.1.9 + publint: 0.1.10 svelte: 3.55.1 svelte-check: 3.0.4_svelte@3.55.1 tslib: 2.5.0 @@ -500,6 +504,15 @@ packages: resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} dev: true + /@inqling/svelte-icons/3.0.2_svelte@3.55.1: + resolution: {integrity: sha512-6ess/qqVgnFwqbBQDcZ5fFjIDDLINOyCf6cJ89y+Fx2HMepTajAIdBF18n4hWvB8OhtySog2+LWEKYyNh8p3rw==} + engines: {pnpm: ^7.0.0} + peerDependencies: + svelte: ^3.55.1 + dependencies: + svelte: 3.55.1 + dev: false + /@jridgewell/resolve-uri/3.1.0: resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} engines: {node: '>=6.0.0'} @@ -557,13 +570,13 @@ packages: fastq: 1.15.0 dev: true - /@playwright/test/1.31.1: - resolution: {integrity: sha512-IsytVZ+0QLDh1Hj83XatGp/GsI1CDJWbyDaBGbainsh0p2zC7F4toUocqowmjS6sQff2NGT3D9WbDj/3K2CJiA==} + /@playwright/test/1.31.2: + resolution: {integrity: sha512-BYVutxDI4JeZKV1+ups6dt5WiqKhjBtIYowyZIJ3kBDmJgsuPKsqqKNIMFbUePLSCmp2cZu+BDL427RcNKTRYw==} engines: {node: '>=14'} hasBin: true dependencies: '@types/node': 18.14.1 - playwright-core: 1.31.1 + playwright-core: 1.31.2 optionalDependencies: fsevents: 2.3.2 dev: true @@ -572,17 +585,17 @@ packages: resolution: {integrity: sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==} dev: true - /@sveltejs/adapter-auto/2.0.0_@sveltejs+kit@1.8.5: + /@sveltejs/adapter-auto/2.0.0_@sveltejs+kit@1.10.0: resolution: {integrity: sha512-b+gkHFZgD771kgV3aO4avHFd7y1zhmMYy9i6xOK7m/rwmwaRO8gnF5zBc0Rgca80B2PMU1bKNxyBTHA14OzUAQ==} peerDependencies: '@sveltejs/kit': ^1.0.0 dependencies: - '@sveltejs/kit': 1.8.5_svelte@3.55.1+vite@4.1.4 + '@sveltejs/kit': 1.10.0_svelte@3.55.1+vite@4.1.4 import-meta-resolve: 2.2.1 dev: true - /@sveltejs/kit/1.8.5_svelte@3.55.1+vite@4.1.4: - resolution: {integrity: sha512-b6kbjVAivoPd3oL9IVBaZBWiuHeI0qBKfszSDXcqsPfiSMyUK7ilHDFVSWNn+2EMPO48+87iuho71yTCOXZE3w==} + /@sveltejs/kit/1.10.0_svelte@3.55.1+vite@4.1.4: + resolution: {integrity: sha512-0P35zHrByfbF3Ym3RdQL+RvzgsCDSyO3imSwuZ67XAD5HoCQFF3a8Mhh0V3sObz3rc5aJd4Qn82UpAihJqZ6gQ==} engines: {node: ^16.14 || >=18} hasBin: true requiresBuild: true @@ -692,8 +705,8 @@ packages: resolution: {integrity: sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==} dev: true - /@typescript-eslint/eslint-plugin/5.53.0_cjo54hduev4bqhpjw5znwiokqu: - resolution: {integrity: sha512-alFpFWNucPLdUOySmXCJpzr6HKC3bu7XooShWM+3w/EL6J2HIoB2PFxpLnq4JauWVk6DiVeNKzQlFEaE+X9sGw==} + /@typescript-eslint/eslint-plugin/5.54.0_6mj2wypvdnknez7kws2nfdgupi: + resolution: {integrity: sha512-+hSN9BdSr629RF02d7mMtXhAJvDTyCbprNYJKrXETlul/Aml6YZwd90XioVbjejQeHbb3R8Dg0CkRgoJDxo8aw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: '@typescript-eslint/parser': ^5.0.0 @@ -703,10 +716,10 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/parser': 5.53.0_ycpbpc6yetojsgtrx3mwntkhsu - '@typescript-eslint/scope-manager': 5.53.0 - '@typescript-eslint/type-utils': 5.53.0_ycpbpc6yetojsgtrx3mwntkhsu - '@typescript-eslint/utils': 5.53.0_ycpbpc6yetojsgtrx3mwntkhsu + '@typescript-eslint/parser': 5.54.0_ycpbpc6yetojsgtrx3mwntkhsu + '@typescript-eslint/scope-manager': 5.54.0 + '@typescript-eslint/type-utils': 5.54.0_ycpbpc6yetojsgtrx3mwntkhsu + '@typescript-eslint/utils': 5.54.0_ycpbpc6yetojsgtrx3mwntkhsu debug: 4.3.4 eslint: 8.35.0 grapheme-splitter: 1.0.4 @@ -720,8 +733,8 @@ packages: - supports-color dev: true - /@typescript-eslint/parser/5.53.0_ycpbpc6yetojsgtrx3mwntkhsu: - resolution: {integrity: sha512-MKBw9i0DLYlmdOb3Oq/526+al20AJZpANdT6Ct9ffxcV8nKCHz63t/S0IhlTFNsBIHJv+GY5SFJ0XfqVeydQrQ==} + /@typescript-eslint/parser/5.54.0_ycpbpc6yetojsgtrx3mwntkhsu: + resolution: {integrity: sha512-aAVL3Mu2qTi+h/r04WI/5PfNWvO6pdhpeMRWk9R7rEV4mwJNzoWf5CCU5vDKBsPIFQFjEq1xg7XBI2rjiMXQbQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -730,9 +743,9 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 5.53.0 - '@typescript-eslint/types': 5.53.0 - '@typescript-eslint/typescript-estree': 5.53.0_typescript@4.9.5 + '@typescript-eslint/scope-manager': 5.54.0 + '@typescript-eslint/types': 5.54.0 + '@typescript-eslint/typescript-estree': 5.54.0_typescript@4.9.5 debug: 4.3.4 eslint: 8.35.0 typescript: 4.9.5 @@ -740,16 +753,16 @@ packages: - supports-color dev: true - /@typescript-eslint/scope-manager/5.53.0: - resolution: {integrity: sha512-Opy3dqNsp/9kBBeCPhkCNR7fmdSQqA+47r21hr9a14Bx0xnkElEQmhoHga+VoaoQ6uDHjDKmQPIYcUcKJifS7w==} + /@typescript-eslint/scope-manager/5.54.0: + resolution: {integrity: sha512-VTPYNZ7vaWtYna9M4oD42zENOBrb+ZYyCNdFs949GcN8Miwn37b8b7eMj+EZaq7VK9fx0Jd+JhmkhjFhvnovhg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - '@typescript-eslint/types': 5.53.0 - '@typescript-eslint/visitor-keys': 5.53.0 + '@typescript-eslint/types': 5.54.0 + '@typescript-eslint/visitor-keys': 5.54.0 dev: true - /@typescript-eslint/type-utils/5.53.0_ycpbpc6yetojsgtrx3mwntkhsu: - resolution: {integrity: sha512-HO2hh0fmtqNLzTAme/KnND5uFNwbsdYhCZghK2SoxGp3Ifn2emv+hi0PBUjzzSh0dstUIFqOj3bp0AwQlK4OWw==} + /@typescript-eslint/type-utils/5.54.0_ycpbpc6yetojsgtrx3mwntkhsu: + resolution: {integrity: sha512-WI+WMJ8+oS+LyflqsD4nlXMsVdzTMYTxl16myXPaCXnSgc7LWwMsjxQFZCK/rVmTZ3FN71Ct78ehO9bRC7erYQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: '*' @@ -758,8 +771,8 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 5.53.0_typescript@4.9.5 - '@typescript-eslint/utils': 5.53.0_ycpbpc6yetojsgtrx3mwntkhsu + '@typescript-eslint/typescript-estree': 5.54.0_typescript@4.9.5 + '@typescript-eslint/utils': 5.54.0_ycpbpc6yetojsgtrx3mwntkhsu debug: 4.3.4 eslint: 8.35.0 tsutils: 3.21.0_typescript@4.9.5 @@ -768,13 +781,13 @@ packages: - supports-color dev: true - /@typescript-eslint/types/5.53.0: - resolution: {integrity: sha512-5kcDL9ZUIP756K6+QOAfPkigJmCPHcLN7Zjdz76lQWWDdzfOhZDTj1irs6gPBKiXx5/6O3L0+AvupAut3z7D2A==} + /@typescript-eslint/types/5.54.0: + resolution: {integrity: sha512-nExy+fDCBEgqblasfeE3aQ3NuafBUxZxgxXcYfzYRZFHdVvk5q60KhCSkG0noHgHRo/xQ/BOzURLZAafFpTkmQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /@typescript-eslint/typescript-estree/5.53.0_typescript@4.9.5: - resolution: {integrity: sha512-eKmipH7QyScpHSkhbptBBYh9v8FxtngLquq292YTEQ1pxVs39yFBlLC1xeIZcPPz1RWGqb7YgERJRGkjw8ZV7w==} + /@typescript-eslint/typescript-estree/5.54.0_typescript@4.9.5: + resolution: {integrity: sha512-X2rJG97Wj/VRo5YxJ8Qx26Zqf0RRKsVHd4sav8NElhbZzhpBI8jU54i6hfo9eheumj4oO4dcRN1B/zIVEqR/MQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: typescript: '*' @@ -782,8 +795,8 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/types': 5.53.0 - '@typescript-eslint/visitor-keys': 5.53.0 + '@typescript-eslint/types': 5.54.0 + '@typescript-eslint/visitor-keys': 5.54.0 debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 @@ -794,17 +807,17 @@ packages: - supports-color dev: true - /@typescript-eslint/utils/5.53.0_ycpbpc6yetojsgtrx3mwntkhsu: - resolution: {integrity: sha512-VUOOtPv27UNWLxFwQK/8+7kvxVC+hPHNsJjzlJyotlaHjLSIgOCKj9I0DBUjwOOA64qjBwx5afAPjksqOxMO0g==} + /@typescript-eslint/utils/5.54.0_ycpbpc6yetojsgtrx3mwntkhsu: + resolution: {integrity: sha512-cuwm8D/Z/7AuyAeJ+T0r4WZmlnlxQ8wt7C7fLpFlKMR+dY6QO79Cq1WpJhvZbMA4ZeZGHiRWnht7ZJ8qkdAunw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: '@types/json-schema': 7.0.11 '@types/semver': 7.3.13 - '@typescript-eslint/scope-manager': 5.53.0 - '@typescript-eslint/types': 5.53.0 - '@typescript-eslint/typescript-estree': 5.53.0_typescript@4.9.5 + '@typescript-eslint/scope-manager': 5.54.0 + '@typescript-eslint/types': 5.54.0 + '@typescript-eslint/typescript-estree': 5.54.0_typescript@4.9.5 eslint: 8.35.0 eslint-scope: 5.1.1 eslint-utils: 3.0.0_eslint@8.35.0 @@ -814,11 +827,11 @@ packages: - typescript dev: true - /@typescript-eslint/visitor-keys/5.53.0: - resolution: {integrity: sha512-JqNLnX3leaHFZEN0gCh81sIvgrp/2GOACZNgO4+Tkf64u51kTpAyWFOY8XHx8XuXr3N2C9zgPPHtcpMg6z1g0w==} + /@typescript-eslint/visitor-keys/5.54.0: + resolution: {integrity: sha512-xu4wT7aRCakGINTLGeyGqDn+78BwFlggwBjnHa1ar/KaGagnmwLYmlrXIrgAaQ3AE1Vd6nLfKASm7LrFHNbKGA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - '@typescript-eslint/types': 5.53.0 + '@typescript-eslint/types': 5.54.0 eslint-visitor-keys: 3.3.0 dev: true @@ -1054,6 +1067,11 @@ packages: engines: {node: '>=0.8'} dev: true + /clsx/1.2.1: + resolution: {integrity: sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==} + engines: {node: '>=6'} + dev: false + /color-convert/1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} dependencies: @@ -2471,8 +2489,8 @@ packages: find-up: 4.1.0 dev: true - /playwright-core/1.31.1: - resolution: {integrity: sha512-JTyX4kV3/LXsvpHkLzL2I36aCdml4zeE35x+G5aPc4bkLsiRiQshU5lWeVpHFAuC8xAcbI6FDcw/8z3q2xtJSQ==} + /playwright-core/1.31.2: + resolution: {integrity: sha512-a1dFgCNQw4vCsG7bnojZjDnPewZcw7tZUNFN0ZkcLYKj+mPmXvg4MpaaKZ5SgqPsOmqIf2YsVRkgqiRDxD+fDQ==} engines: {node: '>=14'} hasBin: true dev: true @@ -2521,8 +2539,8 @@ packages: resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==} dev: true - /publint/0.1.9: - resolution: {integrity: sha512-O53y7vbePxuGFmEjgcrafMSlDpOJwOkj8YdexOt7yWlv7SB3rXoT3mHknyMJ3lf2UFH5Bmt6tnIkHcOTR6dEoA==} + /publint/0.1.10: + resolution: {integrity: sha512-maW+K+S1cN7//l3dfZjgVKczDRyytMNeFryp7TyFJMmqAq6dQRycTyT9x5/Nc8N5yIeSc6G2H96iOShKW1M4mQ==} engines: {node: '>=16'} hasBin: true dependencies: diff --git a/src/app.d.ts b/src/app.d.ts index 465f22f..77dd5ea 100644 --- a/src/app.d.ts +++ b/src/app.d.ts @@ -4,6 +4,7 @@ declare module './lib/types' { interface EpisodeDetails { title: string; + artwork: string; } } diff --git a/src/app.html b/src/app.html index 2f83674..0a6491d 100644 --- a/src/app.html +++ b/src/app.html @@ -6,7 +6,12 @@ %sveltekit.head% - +
%sveltekit.body%
diff --git a/src/lib/audio/audio-element.ts b/src/lib/audio/audio-element.ts index 5f83388..a2178fb 100644 --- a/src/lib/audio/audio-element.ts +++ b/src/lib/audio/audio-element.ts @@ -1,11 +1,11 @@ import { browser } from '$app/environment'; -import { user_preferences } from '$lib/user'; import { onMount } from 'svelte'; import { get, readable } from 'svelte/store'; +import { user_preferences } from '../user'; export const audio_element = readable(null, (set) => { if (!browser) return; - const ID = 'svelte-podcast-generated-audio-element'; + const ID = 'svpod--generated-audio-element'; onMount(() => { const existing_element = document.getElementById(ID) as HTMLAudioElement | null; diff --git a/src/lib/audio/audio-loader.svelte b/src/lib/audio/audio-loader.svelte index e7e49dd..cc38ca7 100644 --- a/src/lib/audio/audio-loader.svelte +++ b/src/lib/audio/audio-loader.svelte @@ -1,9 +1,9 @@ + + + + diff --git a/src/lib/audio/episode-data.ts b/src/lib/audio/episode-data.ts index a105bde..dab136f 100644 --- a/src/lib/audio/episode-data.ts +++ b/src/lib/audio/episode-data.ts @@ -1,10 +1,10 @@ -import { audio_element } from '$lib/audio/audio-element'; -import { episode_details } from '$lib/audio/episode-details'; -import type { EpisodeAttributes, EpisodeDetails } from '$lib/types'; -import { user_preferences, user_progress } from '$lib/user'; -import { warn } from '$lib/utility/package/log'; import clamp from 'just-clamp'; import { derived, get, type Readable } from 'svelte/store'; +import type { EpisodeAttributes, EpisodeDetails } from '../types'; +import { user_preferences, user_progress } from '../user'; +import { warn } from '../utility/package/log'; +import { audio_element } from './audio-element'; +import { episode_details } from './episode-details'; const default_episode_attributes = { will_autoplay: false, diff --git a/src/lib/audio/episode-details.ts b/src/lib/audio/episode-details.ts index 7942a00..cb9c998 100644 --- a/src/lib/audio/episode-details.ts +++ b/src/lib/audio/episode-details.ts @@ -1,4 +1,4 @@ -import type { EpisodeDetails } from '$lib/types'; import { writable } from 'svelte/store'; +import type { EpisodeDetails } from '../types'; export const episode_details = writable(null); diff --git a/src/lib/audio/episode-progress.ts b/src/lib/audio/episode-progress.ts index 8978f00..9d1bbe1 100644 --- a/src/lib/audio/episode-progress.ts +++ b/src/lib/audio/episode-progress.ts @@ -1,7 +1,7 @@ -import { audio_element } from '$lib/audio/audio-element'; -import type { EpisodeProgress } from '$lib/types'; -import { secondsToTimestamp } from '$lib/utility'; import { derived, type Readable } from 'svelte/store'; +import type { EpisodeProgress } from '../types'; +import { secondsToTimestamp } from '../utility'; +import { audio_element } from './audio-element'; const default_episode_progress = { current_time: 0, diff --git a/src/lib/audio/index.ts b/src/lib/audio/index.ts index b39e8f1..d2f5c58 100644 --- a/src/lib/audio/index.ts +++ b/src/lib/audio/index.ts @@ -1,4 +1,4 @@ -export { default as AudioLoader } from '$lib/audio/audio-loader.svelte'; -export * from '$lib/audio/episode-data'; -export * from '$lib/audio/episode-details'; -export * from '$lib/audio/episode-progress'; +export { default as AudioLoader } from './audio-loader.svelte'; +export * from './episode-data'; +export * from './episode-details'; +export * from './episode-progress'; diff --git a/src/lib/components/audio-progress.svelte b/src/lib/components/audio-progress.svelte deleted file mode 100644 index f41f219..0000000 --- a/src/lib/components/audio-progress.svelte +++ /dev/null @@ -1,21 +0,0 @@ - - - - - diff --git a/src/lib/components/headless-timeline.svelte b/src/lib/components/headless-timeline.svelte new file mode 100644 index 0000000..07d928e --- /dev/null +++ b/src/lib/components/headless-timeline.svelte @@ -0,0 +1,145 @@ + + + + + episode_audio.seek(e.currentTarget.valueAsNumber)} + on:touchstart={() => handle_drag_start('touchstart')} + on:mousedown={() => handle_drag_start('mousedown')} + on:touchend={() => handle_drag_end('touchend')} + on:mouseup={() => handle_drag_end('mouseup')} +/> diff --git a/src/lib/components/index.ts b/src/lib/components/index.ts new file mode 100644 index 0000000..5eeb5a7 --- /dev/null +++ b/src/lib/components/index.ts @@ -0,0 +1,3 @@ +export { default as HeadlessTimeline } from './headless-timeline.svelte'; +export { default as PlayerStack } from './player-stack.svelte'; +export { default as PlayerWidget } from './player-widget.svelte'; diff --git a/src/lib/components/player-stack.svelte b/src/lib/components/player-stack.svelte new file mode 100644 index 0000000..d384730 --- /dev/null +++ b/src/lib/components/player-stack.svelte @@ -0,0 +1,318 @@ + + + + +
+
+ + + + {#if is_loaded} + + {:else} +
+ +
+ {/if} + + +
+ +
+ + +
+ +
+
+
+ +
+ +
+ + {#if options.timestamps || options.playback_rate} +
+ {#if options.timestamps} +
+ +
+ +
+ +
+ +
+ {/if} + + {#if options.playback_rate} + + {/if} +
+ {/if} +
diff --git a/src/lib/components/player-widget.svelte b/src/lib/components/player-widget.svelte new file mode 100644 index 0000000..6ce6849 --- /dev/null +++ b/src/lib/components/player-widget.svelte @@ -0,0 +1,234 @@ + + + + +
+ {#if options.skip_back} + + {/if} + + + {#if is_loaded} + + {:else} +
+ +
+ {/if} + + {#if options.skip_forward} + + {/if} + + {#if current_time !== false} +
+ +
+ {/if} +
+ +
+ {#if duration !== false} +
+ +
+ {/if} + {#if options.playback_rate} + + {/if} +
diff --git a/src/lib/components/utility/a11y-icon.svelte b/src/lib/components/utility/a11y-icon.svelte new file mode 100644 index 0000000..b751a1b --- /dev/null +++ b/src/lib/components/utility/a11y-icon.svelte @@ -0,0 +1,9 @@ + + + +{label} diff --git a/src/lib/components/utility/index.ts b/src/lib/components/utility/index.ts new file mode 100644 index 0000000..40fb8e0 --- /dev/null +++ b/src/lib/components/utility/index.ts @@ -0,0 +1,4 @@ +export { default as A11yIcon } from './a11y-icon.svelte'; +export { default as Skip } from './skip.svelte'; +export { default as Spinner } from './spinner.svelte'; +export { default as Timestamp } from './timestamp.svelte'; diff --git a/src/lib/components/utility/skip.svelte b/src/lib/components/utility/skip.svelte new file mode 100644 index 0000000..906ec54 --- /dev/null +++ b/src/lib/components/utility/skip.svelte @@ -0,0 +1,155 @@ + + + + +
+ + skip {type} + {value} + seconds + + +
+ {#if type === 'forward'} + + + + + + + + + + + {:else} + + + + + + + + + + + {/if} +
+
diff --git a/src/lib/components/utility/spinner.svelte b/src/lib/components/utility/spinner.svelte new file mode 100644 index 0000000..6e0c6ab --- /dev/null +++ b/src/lib/components/utility/spinner.svelte @@ -0,0 +1,62 @@ + + + + +
+ {#each [0, 0.075, 0.15] as delay} +
+ + + +
+ {/each} +
diff --git a/src/lib/components/utility/timestamp.svelte b/src/lib/components/utility/timestamp.svelte new file mode 100644 index 0000000..f8d5598 --- /dev/null +++ b/src/lib/components/utility/timestamp.svelte @@ -0,0 +1,19 @@ + + + + +{timestamp} diff --git a/src/lib/index.ts b/src/lib/index.ts index d9ba206..37a0db5 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -1,3 +1,4 @@ -export * from '$lib/audio'; -export * from '$lib/user'; -export * from '$lib/utility'; +export * from './audio'; +export * from './components'; +export * from './user'; +export * from './utility'; diff --git a/src/lib/user/preferences.ts b/src/lib/user/preferences.ts index ee35947..0eeb489 100644 --- a/src/lib/user/preferences.ts +++ b/src/lib/user/preferences.ts @@ -1,6 +1,6 @@ -import type { UserPreferences } from '$lib/types'; import clamp from 'just-clamp'; import { persisted } from 'svelte-local-storage-store'; +import type { UserPreferences } from '../types'; const _default_user_preferences = { playback_rate: 1, volume: 1 } satisfies UserPreferences; const _user_preferences = persisted('USER_PREFERENCE', _default_user_preferences); diff --git a/src/lib/user/progress.ts b/src/lib/user/progress.ts index 1529860..9f51965 100644 --- a/src/lib/user/progress.ts +++ b/src/lib/user/progress.ts @@ -1,9 +1,9 @@ -import { episode_audio, episode_progress } from '$lib/audio'; -import type { UserProgress } from '$lib/types'; -import { get_pathname_from_url } from '$lib/utility/get-pathname-from-url'; -import { info } from '$lib/utility/package/log'; import { persisted } from 'svelte-local-storage-store'; import { get } from 'svelte/store'; +import { episode_audio, episode_progress } from '../audio'; +import type { UserProgress } from '../types'; +import { get_pathname_from_url } from '../utility'; +import { info } from '../utility/package/log'; const _default_user_progress = {} satisfies UserProgress; const _user_progress = persisted('USER_PROGRESS', _default_user_progress); diff --git a/src/lib/utility/index.ts b/src/lib/utility/index.ts index 9c31b07..465ca9b 100644 --- a/src/lib/utility/index.ts +++ b/src/lib/utility/index.ts @@ -1 +1,2 @@ +export * from './get-pathname-from-url'; export * from './seconds-to-timestamp'; diff --git a/src/lib/utility/package/log.ts b/src/lib/utility/package/log.ts index 268cc89..d61bcbc 100644 --- a/src/lib/utility/package/log.ts +++ b/src/lib/utility/package/log.ts @@ -1,8 +1,8 @@ import { dev } from '$app/environment'; const useLogger = { - error: console.error, info: console.info, + error: console.error, warn: console.warn, }; @@ -13,7 +13,11 @@ export function log(type: Logger, ...content: unknown[]) { if (type === 'info' && !dev) return; - logger('🔊 svelte-podcast: ', ...content); + logger( + '%c🔊 svelte-podcast:', + 'color: #FF3E00; background-color: rgba(255, 62, 0, 0.15); padding: 4px 8px; border-radius:4px;', + ...content, + ); } export const info = (...content: unknown[]) => log('info', ...content); diff --git a/src/lib/utility/seconds-to-timestamp.ts b/src/lib/utility/seconds-to-timestamp.ts index 5bd152f..8decbe8 100644 --- a/src/lib/utility/seconds-to-timestamp.ts +++ b/src/lib/utility/seconds-to-timestamp.ts @@ -3,14 +3,14 @@ function section(t: number) { return t; } -export function secondsToTimestamp(seconds: number) { +export function secondsToTimestamp(seconds: number, force_hours = false) { const hh = Math.floor(seconds / 3600); const hh_remainder = seconds % 3600; const mm = Math.floor(hh_remainder / 60); const mm_remainder = hh_remainder % 60; const ss = Math.floor(mm_remainder); - const hrs = hh > 0 ? `${section(hh)}:` : ''; + const hrs = force_hours || hh > 0 ? `${section(hh)}:` : ''; const mins = mm ? `${section(mm)}:` : '00:'; const secs = ss ? `${section(ss)}` : '00'; diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 419f6c7..c2d8e0a 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -1,5 +1,5 @@ diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 3cc263a..f0ff9cd 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -1,5 +1,12 @@
{JSON.stringify(
@@ -25,7 +34,7 @@
 			$user_preferences,
 		},
 		null,
-		3,
+		2,
 	)}

Demo

@@ -34,7 +43,7 @@
Load Audio
- @@ -80,3 +80,51 @@ {rate}x {/each} + +
+ + + +
+ +
+
+ +
+
+ +
+
+ + +
+
+ +
+
+ +
+
+ +
+
+ diff --git a/src/routes/another-page/+page.svelte b/src/routes/another-page/+page.svelte index 5f343cc..f723bc4 100644 --- a/src/routes/another-page/+page.svelte +++ b/src/routes/another-page/+page.svelte @@ -1,16 +1,108 @@ -

Demo

- -Demo -
{JSON.stringify(
 		{
 			$episode_audio,
 			$episode_progress,
+			$user_preferences,
 		},
 		null,
-		3,
+		2,
 	)}
+ +

Demo

+Another Page + + + +
Load Audio
+ + + + +
Custom audio controls
+ +
Play / Pause Actions
+ + + + + +
Audio Actions
+ + + + + +
Seeking
+ + + + + + +
Playback Rate
+ +{#each [0.5, 1, 2, 3] as rate} + +{/each} + +
+ + + +
+ +
+
+ +
+
+ +
+
+ diff --git a/svelte.config.js b/svelte.config.js index b91762c..ec50a99 100644 --- a/svelte.config.js +++ b/svelte.config.js @@ -10,8 +10,7 @@ const config = { kit: { adapter: adapter(), alias: { - $lib: 'src/lib', - $pkg: 'src/lib/utility/package/', + 'svelte-podcast': 'src/lib', }, }, };