Podcast player components (#37)
This commit is contained in:
@@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
'svelte-podcast': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Improves theming with css variables
|
||||||
|
Improves developer logs
|
||||||
|
Fixes various package export issues
|
||||||
|
Adds player components:
|
||||||
|
|
||||||
|
- Player: `<PlayerStack />`
|
||||||
|
- Player: `<PlayerWidget />`
|
||||||
|
- Utility: `<HeadlessTimeline />`
|
||||||
@@ -12,3 +12,5 @@ node_modules
|
|||||||
pnpm-lock.yaml
|
pnpm-lock.yaml
|
||||||
package-lock.json
|
package-lock.json
|
||||||
yarn.lock
|
yarn.lock
|
||||||
|
|
||||||
|
**/components/_*
|
||||||
@@ -17,4 +17,7 @@ module.exports = {
|
|||||||
es2017: true,
|
es2017: true,
|
||||||
node: true,
|
node: true,
|
||||||
},
|
},
|
||||||
|
rules: {
|
||||||
|
'no-restricted-imports': ['error', { patterns: ['$lib', '$lib/*'] }],
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,3 +9,4 @@ node_modules
|
|||||||
!.env.example
|
!.env.example
|
||||||
vite.config.js.timestamp-*
|
vite.config.js.timestamp-*
|
||||||
vite.config.ts.timestamp-*
|
vite.config.ts.timestamp-*
|
||||||
|
.eslintcache
|
||||||
@@ -4,6 +4,9 @@
|
|||||||
"trailingComma": "all",
|
"trailingComma": "all",
|
||||||
"printWidth": 100,
|
"printWidth": 100,
|
||||||
"plugins": ["prettier-plugin-svelte"],
|
"plugins": ["prettier-plugin-svelte"],
|
||||||
|
"svelteSortOrder": "options-scripts-styles-markup",
|
||||||
|
"svelteBracketNewLine": true,
|
||||||
|
"svelteIndentScriptAndStyle": true,
|
||||||
"pluginSearchDirs": ["."],
|
"pluginSearchDirs": ["."],
|
||||||
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
|
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+1
@@ -2,6 +2,7 @@
|
|||||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||||
// for the documentation about the extensions.json format
|
// for the documentation about the extensions.json format
|
||||||
"recommendations": [
|
"recommendations": [
|
||||||
|
"dbaeumer.vscode-eslint",
|
||||||
"aaron-bond.better-comments",
|
"aaron-bond.better-comments",
|
||||||
"esbenp.prettier-vscode",
|
"esbenp.prettier-vscode",
|
||||||
"gruntfuggly.todo-tree"
|
"gruntfuggly.todo-tree"
|
||||||
|
|||||||
Vendored
+4
-1
@@ -7,6 +7,7 @@
|
|||||||
"source.organizeImports": true
|
"source.organizeImports": true
|
||||||
},
|
},
|
||||||
"eslint.packageManager": "pnpm",
|
"eslint.packageManager": "pnpm",
|
||||||
|
"eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact", "svelte"],
|
||||||
"files.exclude": {
|
"files.exclude": {
|
||||||
"**/.DS_Store": true,
|
"**/.DS_Store": true,
|
||||||
"**/*-lock.*": true,
|
"**/*-lock.*": true,
|
||||||
@@ -21,5 +22,7 @@
|
|||||||
"**/.svelte-kit": true
|
"**/.svelte-kit": true
|
||||||
},
|
},
|
||||||
"problems.sortOrder": "severity",
|
"problems.sortOrder": "severity",
|
||||||
"todo-tree.tree.scanMode": "workspace only"
|
"todo-tree.tree.scanMode": "workspace only",
|
||||||
|
"javascript.preferences.importModuleSpecifier": "relative",
|
||||||
|
"typescript.preferences.importModuleSpecifier": "relative"
|
||||||
}
|
}
|
||||||
|
|||||||
+21
-17
@@ -19,7 +19,9 @@
|
|||||||
"test": "playwright test",
|
"test": "playwright test",
|
||||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
"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=. .",
|
"format": "prettier --write --plugin-search-dir=. .",
|
||||||
"release": "pnpm package && changeset publish",
|
"release": "pnpm package && changeset publish",
|
||||||
"ts": "tsc --pretty --noImplicitAny --noEmit"
|
"ts": "tsc --pretty --noImplicitAny --noEmit"
|
||||||
@@ -34,31 +36,33 @@
|
|||||||
"dist"
|
"dist"
|
||||||
],
|
],
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"svelte": "^3.54.0"
|
"svelte": "^3.55.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@inqling/svelte-icons": "^3.0.2",
|
||||||
|
"clsx": "^1.2.1",
|
||||||
"just-clamp": "^4.2.0",
|
"just-clamp": "^4.2.0",
|
||||||
"svelte-local-storage-store": "^0.4.0"
|
"svelte-local-storage-store": "^0.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@changesets/cli": "^2.26.0",
|
"@changesets/cli": "^2.26.0",
|
||||||
"@playwright/test": "^1.28.1",
|
"@playwright/test": "^1.31.2",
|
||||||
"@sveltejs/adapter-auto": "^2.0.0",
|
"@sveltejs/adapter-auto": "^2.0.0",
|
||||||
"@sveltejs/kit": "^1.5.0",
|
"@sveltejs/kit": "^1.10.0",
|
||||||
"@sveltejs/package": "^2.0.0",
|
"@sveltejs/package": "^2.0.2",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.45.0",
|
"@typescript-eslint/eslint-plugin": "^5.54.0",
|
||||||
"@typescript-eslint/parser": "^5.45.0",
|
"@typescript-eslint/parser": "^5.54.0",
|
||||||
"eslint": "^8.28.0",
|
"eslint": "^8.35.0",
|
||||||
"eslint-config-prettier": "^8.5.0",
|
"eslint-config-prettier": "^8.6.0",
|
||||||
"eslint-plugin-svelte3": "^4.0.0",
|
"eslint-plugin-svelte3": "^4.0.0",
|
||||||
"prettier": "^2.8.0",
|
"prettier": "^2.8.4",
|
||||||
"prettier-plugin-svelte": "^2.8.1",
|
"prettier-plugin-svelte": "^2.9.0",
|
||||||
"publint": "^0.1.9",
|
"publint": "^0.1.10",
|
||||||
"svelte": "^3.54.0",
|
"svelte": "^3.55.1",
|
||||||
"svelte-check": "^3.0.1",
|
"svelte-check": "^3.0.4",
|
||||||
"tslib": "^2.4.1",
|
"tslib": "^2.5.0",
|
||||||
"typescript": "^4.9.3",
|
"typescript": "^4.9.5",
|
||||||
"vite": "^4.0.0"
|
"vite": "^4.1.4"
|
||||||
},
|
},
|
||||||
"svelte": "./dist/index.js",
|
"svelte": "./dist/index.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
|
|||||||
Generated
+83
-65
@@ -2,44 +2,48 @@ lockfileVersion: 5.4
|
|||||||
|
|
||||||
specifiers:
|
specifiers:
|
||||||
'@changesets/cli': ^2.26.0
|
'@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/adapter-auto': ^2.0.0
|
||||||
'@sveltejs/kit': ^1.5.0
|
'@sveltejs/kit': ^1.10.0
|
||||||
'@sveltejs/package': ^2.0.0
|
'@sveltejs/package': ^2.0.2
|
||||||
'@typescript-eslint/eslint-plugin': ^5.45.0
|
'@typescript-eslint/eslint-plugin': ^5.54.0
|
||||||
'@typescript-eslint/parser': ^5.45.0
|
'@typescript-eslint/parser': ^5.54.0
|
||||||
eslint: ^8.28.0
|
clsx: ^1.2.1
|
||||||
eslint-config-prettier: ^8.5.0
|
eslint: ^8.35.0
|
||||||
|
eslint-config-prettier: ^8.6.0
|
||||||
eslint-plugin-svelte3: ^4.0.0
|
eslint-plugin-svelte3: ^4.0.0
|
||||||
just-clamp: ^4.2.0
|
just-clamp: ^4.2.0
|
||||||
prettier: ^2.8.0
|
prettier: ^2.8.4
|
||||||
prettier-plugin-svelte: ^2.8.1
|
prettier-plugin-svelte: ^2.9.0
|
||||||
publint: ^0.1.9
|
publint: ^0.1.10
|
||||||
svelte: ^3.54.0
|
svelte: ^3.55.1
|
||||||
svelte-check: ^3.0.1
|
svelte-check: ^3.0.4
|
||||||
svelte-local-storage-store: ^0.4.0
|
svelte-local-storage-store: ^0.4.0
|
||||||
tslib: ^2.4.1
|
tslib: ^2.5.0
|
||||||
typescript: ^4.9.3
|
typescript: ^4.9.5
|
||||||
vite: ^4.0.0
|
vite: ^4.1.4
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@inqling/svelte-icons': 3.0.2_svelte@3.55.1
|
||||||
|
clsx: 1.2.1
|
||||||
just-clamp: 4.2.0
|
just-clamp: 4.2.0
|
||||||
svelte-local-storage-store: 0.4.0_svelte@3.55.1
|
svelte-local-storage-store: 0.4.0_svelte@3.55.1
|
||||||
|
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@changesets/cli': 2.26.0
|
'@changesets/cli': 2.26.0
|
||||||
'@playwright/test': 1.31.1
|
'@playwright/test': 1.31.2
|
||||||
'@sveltejs/adapter-auto': 2.0.0_@sveltejs+kit@1.8.5
|
'@sveltejs/adapter-auto': 2.0.0_@sveltejs+kit@1.10.0
|
||||||
'@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
|
||||||
'@sveltejs/package': 2.0.2_4x7phaipmicbaooxtnresslofa
|
'@sveltejs/package': 2.0.2_4x7phaipmicbaooxtnresslofa
|
||||||
'@typescript-eslint/eslint-plugin': 5.53.0_cjo54hduev4bqhpjw5znwiokqu
|
'@typescript-eslint/eslint-plugin': 5.54.0_6mj2wypvdnknez7kws2nfdgupi
|
||||||
'@typescript-eslint/parser': 5.53.0_ycpbpc6yetojsgtrx3mwntkhsu
|
'@typescript-eslint/parser': 5.54.0_ycpbpc6yetojsgtrx3mwntkhsu
|
||||||
eslint: 8.35.0
|
eslint: 8.35.0
|
||||||
eslint-config-prettier: 8.6.0_eslint@8.35.0
|
eslint-config-prettier: 8.6.0_eslint@8.35.0
|
||||||
eslint-plugin-svelte3: 4.0.0_n4ieifq2d7jq3sqoe474cgqlim
|
eslint-plugin-svelte3: 4.0.0_n4ieifq2d7jq3sqoe474cgqlim
|
||||||
prettier: 2.8.4
|
prettier: 2.8.4
|
||||||
prettier-plugin-svelte: 2.9.0_jrsxveqmsx2uadbqiuq74wlc4u
|
prettier-plugin-svelte: 2.9.0_jrsxveqmsx2uadbqiuq74wlc4u
|
||||||
publint: 0.1.9
|
publint: 0.1.10
|
||||||
svelte: 3.55.1
|
svelte: 3.55.1
|
||||||
svelte-check: 3.0.4_svelte@3.55.1
|
svelte-check: 3.0.4_svelte@3.55.1
|
||||||
tslib: 2.5.0
|
tslib: 2.5.0
|
||||||
@@ -500,6 +504,15 @@ packages:
|
|||||||
resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==}
|
resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==}
|
||||||
dev: true
|
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:
|
/@jridgewell/resolve-uri/3.1.0:
|
||||||
resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==}
|
resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==}
|
||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
@@ -557,13 +570,13 @@ packages:
|
|||||||
fastq: 1.15.0
|
fastq: 1.15.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@playwright/test/1.31.1:
|
/@playwright/test/1.31.2:
|
||||||
resolution: {integrity: sha512-IsytVZ+0QLDh1Hj83XatGp/GsI1CDJWbyDaBGbainsh0p2zC7F4toUocqowmjS6sQff2NGT3D9WbDj/3K2CJiA==}
|
resolution: {integrity: sha512-BYVutxDI4JeZKV1+ups6dt5WiqKhjBtIYowyZIJ3kBDmJgsuPKsqqKNIMFbUePLSCmp2cZu+BDL427RcNKTRYw==}
|
||||||
engines: {node: '>=14'}
|
engines: {node: '>=14'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 18.14.1
|
'@types/node': 18.14.1
|
||||||
playwright-core: 1.31.1
|
playwright-core: 1.31.2
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents: 2.3.2
|
fsevents: 2.3.2
|
||||||
dev: true
|
dev: true
|
||||||
@@ -572,17 +585,17 @@ packages:
|
|||||||
resolution: {integrity: sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==}
|
resolution: {integrity: sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==}
|
||||||
dev: true
|
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==}
|
resolution: {integrity: sha512-b+gkHFZgD771kgV3aO4avHFd7y1zhmMYy9i6xOK7m/rwmwaRO8gnF5zBc0Rgca80B2PMU1bKNxyBTHA14OzUAQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@sveltejs/kit': ^1.0.0
|
'@sveltejs/kit': ^1.0.0
|
||||||
dependencies:
|
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
|
import-meta-resolve: 2.2.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@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:
|
||||||
resolution: {integrity: sha512-b6kbjVAivoPd3oL9IVBaZBWiuHeI0qBKfszSDXcqsPfiSMyUK7ilHDFVSWNn+2EMPO48+87iuho71yTCOXZE3w==}
|
resolution: {integrity: sha512-0P35zHrByfbF3Ym3RdQL+RvzgsCDSyO3imSwuZ67XAD5HoCQFF3a8Mhh0V3sObz3rc5aJd4Qn82UpAihJqZ6gQ==}
|
||||||
engines: {node: ^16.14 || >=18}
|
engines: {node: ^16.14 || >=18}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
@@ -692,8 +705,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==}
|
resolution: {integrity: sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@typescript-eslint/eslint-plugin/5.53.0_cjo54hduev4bqhpjw5znwiokqu:
|
/@typescript-eslint/eslint-plugin/5.54.0_6mj2wypvdnknez7kws2nfdgupi:
|
||||||
resolution: {integrity: sha512-alFpFWNucPLdUOySmXCJpzr6HKC3bu7XooShWM+3w/EL6J2HIoB2PFxpLnq4JauWVk6DiVeNKzQlFEaE+X9sGw==}
|
resolution: {integrity: sha512-+hSN9BdSr629RF02d7mMtXhAJvDTyCbprNYJKrXETlul/Aml6YZwd90XioVbjejQeHbb3R8Dg0CkRgoJDxo8aw==}
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@typescript-eslint/parser': ^5.0.0
|
'@typescript-eslint/parser': ^5.0.0
|
||||||
@@ -703,10 +716,10 @@ packages:
|
|||||||
typescript:
|
typescript:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/parser': 5.53.0_ycpbpc6yetojsgtrx3mwntkhsu
|
'@typescript-eslint/parser': 5.54.0_ycpbpc6yetojsgtrx3mwntkhsu
|
||||||
'@typescript-eslint/scope-manager': 5.53.0
|
'@typescript-eslint/scope-manager': 5.54.0
|
||||||
'@typescript-eslint/type-utils': 5.53.0_ycpbpc6yetojsgtrx3mwntkhsu
|
'@typescript-eslint/type-utils': 5.54.0_ycpbpc6yetojsgtrx3mwntkhsu
|
||||||
'@typescript-eslint/utils': 5.53.0_ycpbpc6yetojsgtrx3mwntkhsu
|
'@typescript-eslint/utils': 5.54.0_ycpbpc6yetojsgtrx3mwntkhsu
|
||||||
debug: 4.3.4
|
debug: 4.3.4
|
||||||
eslint: 8.35.0
|
eslint: 8.35.0
|
||||||
grapheme-splitter: 1.0.4
|
grapheme-splitter: 1.0.4
|
||||||
@@ -720,8 +733,8 @@ packages:
|
|||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@typescript-eslint/parser/5.53.0_ycpbpc6yetojsgtrx3mwntkhsu:
|
/@typescript-eslint/parser/5.54.0_ycpbpc6yetojsgtrx3mwntkhsu:
|
||||||
resolution: {integrity: sha512-MKBw9i0DLYlmdOb3Oq/526+al20AJZpANdT6Ct9ffxcV8nKCHz63t/S0IhlTFNsBIHJv+GY5SFJ0XfqVeydQrQ==}
|
resolution: {integrity: sha512-aAVL3Mu2qTi+h/r04WI/5PfNWvO6pdhpeMRWk9R7rEV4mwJNzoWf5CCU5vDKBsPIFQFjEq1xg7XBI2rjiMXQbQ==}
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
|
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
|
||||||
@@ -730,9 +743,9 @@ packages:
|
|||||||
typescript:
|
typescript:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/scope-manager': 5.53.0
|
'@typescript-eslint/scope-manager': 5.54.0
|
||||||
'@typescript-eslint/types': 5.53.0
|
'@typescript-eslint/types': 5.54.0
|
||||||
'@typescript-eslint/typescript-estree': 5.53.0_typescript@4.9.5
|
'@typescript-eslint/typescript-estree': 5.54.0_typescript@4.9.5
|
||||||
debug: 4.3.4
|
debug: 4.3.4
|
||||||
eslint: 8.35.0
|
eslint: 8.35.0
|
||||||
typescript: 4.9.5
|
typescript: 4.9.5
|
||||||
@@ -740,16 +753,16 @@ packages:
|
|||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@typescript-eslint/scope-manager/5.53.0:
|
/@typescript-eslint/scope-manager/5.54.0:
|
||||||
resolution: {integrity: sha512-Opy3dqNsp/9kBBeCPhkCNR7fmdSQqA+47r21hr9a14Bx0xnkElEQmhoHga+VoaoQ6uDHjDKmQPIYcUcKJifS7w==}
|
resolution: {integrity: sha512-VTPYNZ7vaWtYna9M4oD42zENOBrb+ZYyCNdFs949GcN8Miwn37b8b7eMj+EZaq7VK9fx0Jd+JhmkhjFhvnovhg==}
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/types': 5.53.0
|
'@typescript-eslint/types': 5.54.0
|
||||||
'@typescript-eslint/visitor-keys': 5.53.0
|
'@typescript-eslint/visitor-keys': 5.54.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@typescript-eslint/type-utils/5.53.0_ycpbpc6yetojsgtrx3mwntkhsu:
|
/@typescript-eslint/type-utils/5.54.0_ycpbpc6yetojsgtrx3mwntkhsu:
|
||||||
resolution: {integrity: sha512-HO2hh0fmtqNLzTAme/KnND5uFNwbsdYhCZghK2SoxGp3Ifn2emv+hi0PBUjzzSh0dstUIFqOj3bp0AwQlK4OWw==}
|
resolution: {integrity: sha512-WI+WMJ8+oS+LyflqsD4nlXMsVdzTMYTxl16myXPaCXnSgc7LWwMsjxQFZCK/rVmTZ3FN71Ct78ehO9bRC7erYQ==}
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
eslint: '*'
|
eslint: '*'
|
||||||
@@ -758,8 +771,8 @@ packages:
|
|||||||
typescript:
|
typescript:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/typescript-estree': 5.53.0_typescript@4.9.5
|
'@typescript-eslint/typescript-estree': 5.54.0_typescript@4.9.5
|
||||||
'@typescript-eslint/utils': 5.53.0_ycpbpc6yetojsgtrx3mwntkhsu
|
'@typescript-eslint/utils': 5.54.0_ycpbpc6yetojsgtrx3mwntkhsu
|
||||||
debug: 4.3.4
|
debug: 4.3.4
|
||||||
eslint: 8.35.0
|
eslint: 8.35.0
|
||||||
tsutils: 3.21.0_typescript@4.9.5
|
tsutils: 3.21.0_typescript@4.9.5
|
||||||
@@ -768,13 +781,13 @@ packages:
|
|||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@typescript-eslint/types/5.53.0:
|
/@typescript-eslint/types/5.54.0:
|
||||||
resolution: {integrity: sha512-5kcDL9ZUIP756K6+QOAfPkigJmCPHcLN7Zjdz76lQWWDdzfOhZDTj1irs6gPBKiXx5/6O3L0+AvupAut3z7D2A==}
|
resolution: {integrity: sha512-nExy+fDCBEgqblasfeE3aQ3NuafBUxZxgxXcYfzYRZFHdVvk5q60KhCSkG0noHgHRo/xQ/BOzURLZAafFpTkmQ==}
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@typescript-eslint/typescript-estree/5.53.0_typescript@4.9.5:
|
/@typescript-eslint/typescript-estree/5.54.0_typescript@4.9.5:
|
||||||
resolution: {integrity: sha512-eKmipH7QyScpHSkhbptBBYh9v8FxtngLquq292YTEQ1pxVs39yFBlLC1xeIZcPPz1RWGqb7YgERJRGkjw8ZV7w==}
|
resolution: {integrity: sha512-X2rJG97Wj/VRo5YxJ8Qx26Zqf0RRKsVHd4sav8NElhbZzhpBI8jU54i6hfo9eheumj4oO4dcRN1B/zIVEqR/MQ==}
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
typescript: '*'
|
typescript: '*'
|
||||||
@@ -782,8 +795,8 @@ packages:
|
|||||||
typescript:
|
typescript:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/types': 5.53.0
|
'@typescript-eslint/types': 5.54.0
|
||||||
'@typescript-eslint/visitor-keys': 5.53.0
|
'@typescript-eslint/visitor-keys': 5.54.0
|
||||||
debug: 4.3.4
|
debug: 4.3.4
|
||||||
globby: 11.1.0
|
globby: 11.1.0
|
||||||
is-glob: 4.0.3
|
is-glob: 4.0.3
|
||||||
@@ -794,17 +807,17 @@ packages:
|
|||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@typescript-eslint/utils/5.53.0_ycpbpc6yetojsgtrx3mwntkhsu:
|
/@typescript-eslint/utils/5.54.0_ycpbpc6yetojsgtrx3mwntkhsu:
|
||||||
resolution: {integrity: sha512-VUOOtPv27UNWLxFwQK/8+7kvxVC+hPHNsJjzlJyotlaHjLSIgOCKj9I0DBUjwOOA64qjBwx5afAPjksqOxMO0g==}
|
resolution: {integrity: sha512-cuwm8D/Z/7AuyAeJ+T0r4WZmlnlxQ8wt7C7fLpFlKMR+dY6QO79Cq1WpJhvZbMA4ZeZGHiRWnht7ZJ8qkdAunw==}
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
|
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/json-schema': 7.0.11
|
'@types/json-schema': 7.0.11
|
||||||
'@types/semver': 7.3.13
|
'@types/semver': 7.3.13
|
||||||
'@typescript-eslint/scope-manager': 5.53.0
|
'@typescript-eslint/scope-manager': 5.54.0
|
||||||
'@typescript-eslint/types': 5.53.0
|
'@typescript-eslint/types': 5.54.0
|
||||||
'@typescript-eslint/typescript-estree': 5.53.0_typescript@4.9.5
|
'@typescript-eslint/typescript-estree': 5.54.0_typescript@4.9.5
|
||||||
eslint: 8.35.0
|
eslint: 8.35.0
|
||||||
eslint-scope: 5.1.1
|
eslint-scope: 5.1.1
|
||||||
eslint-utils: 3.0.0_eslint@8.35.0
|
eslint-utils: 3.0.0_eslint@8.35.0
|
||||||
@@ -814,11 +827,11 @@ packages:
|
|||||||
- typescript
|
- typescript
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@typescript-eslint/visitor-keys/5.53.0:
|
/@typescript-eslint/visitor-keys/5.54.0:
|
||||||
resolution: {integrity: sha512-JqNLnX3leaHFZEN0gCh81sIvgrp/2GOACZNgO4+Tkf64u51kTpAyWFOY8XHx8XuXr3N2C9zgPPHtcpMg6z1g0w==}
|
resolution: {integrity: sha512-xu4wT7aRCakGINTLGeyGqDn+78BwFlggwBjnHa1ar/KaGagnmwLYmlrXIrgAaQ3AE1Vd6nLfKASm7LrFHNbKGA==}
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/types': 5.53.0
|
'@typescript-eslint/types': 5.54.0
|
||||||
eslint-visitor-keys: 3.3.0
|
eslint-visitor-keys: 3.3.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
@@ -1054,6 +1067,11 @@ packages:
|
|||||||
engines: {node: '>=0.8'}
|
engines: {node: '>=0.8'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/clsx/1.2.1:
|
||||||
|
resolution: {integrity: sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/color-convert/1.9.3:
|
/color-convert/1.9.3:
|
||||||
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
|
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -2471,8 +2489,8 @@ packages:
|
|||||||
find-up: 4.1.0
|
find-up: 4.1.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/playwright-core/1.31.1:
|
/playwright-core/1.31.2:
|
||||||
resolution: {integrity: sha512-JTyX4kV3/LXsvpHkLzL2I36aCdml4zeE35x+G5aPc4bkLsiRiQshU5lWeVpHFAuC8xAcbI6FDcw/8z3q2xtJSQ==}
|
resolution: {integrity: sha512-a1dFgCNQw4vCsG7bnojZjDnPewZcw7tZUNFN0ZkcLYKj+mPmXvg4MpaaKZ5SgqPsOmqIf2YsVRkgqiRDxD+fDQ==}
|
||||||
engines: {node: '>=14'}
|
engines: {node: '>=14'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
dev: true
|
dev: true
|
||||||
@@ -2521,8 +2539,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==}
|
resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/publint/0.1.9:
|
/publint/0.1.10:
|
||||||
resolution: {integrity: sha512-O53y7vbePxuGFmEjgcrafMSlDpOJwOkj8YdexOt7yWlv7SB3rXoT3mHknyMJ3lf2UFH5Bmt6tnIkHcOTR6dEoA==}
|
resolution: {integrity: sha512-maW+K+S1cN7//l3dfZjgVKczDRyytMNeFryp7TyFJMmqAq6dQRycTyT9x5/Nc8N5yIeSc6G2H96iOShKW1M4mQ==}
|
||||||
engines: {node: '>=16'}
|
engines: {node: '>=16'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|||||||
Vendored
+1
@@ -4,6 +4,7 @@
|
|||||||
declare module './lib/types' {
|
declare module './lib/types' {
|
||||||
interface EpisodeDetails {
|
interface EpisodeDetails {
|
||||||
title: string;
|
title: string;
|
||||||
|
artwork: string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-1
@@ -6,7 +6,12 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
%sveltekit.head%
|
%sveltekit.head%
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body
|
||||||
|
style="
|
||||||
|
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu,
|
||||||
|
Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
||||||
|
"
|
||||||
|
>
|
||||||
<div>%sveltekit.body%</div>
|
<div>%sveltekit.body%</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { browser } from '$app/environment';
|
import { browser } from '$app/environment';
|
||||||
import { user_preferences } from '$lib/user';
|
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { get, readable } from 'svelte/store';
|
import { get, readable } from 'svelte/store';
|
||||||
|
import { user_preferences } from '../user';
|
||||||
|
|
||||||
export const audio_element = readable<HTMLAudioElement | null>(null, (set) => {
|
export const audio_element = readable<HTMLAudioElement | null>(null, (set) => {
|
||||||
if (!browser) return;
|
if (!browser) return;
|
||||||
const ID = 'svelte-podcast-generated-audio-element';
|
const ID = 'svpod--generated-audio-element';
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
const existing_element = document.getElementById(ID) as HTMLAudioElement | null;
|
const existing_element = document.getElementById(ID) as HTMLAudioElement | null;
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { audio_element } from '$lib/audio/audio-element';
|
|
||||||
import { user_preferences } from '$lib/user';
|
|
||||||
import { info, warn } from '$lib/utility/package/log';
|
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { get } from 'svelte/store';
|
import { get } from 'svelte/store';
|
||||||
|
import { user_preferences } from '../user';
|
||||||
|
import { info, warn } from '../utility/package/log';
|
||||||
|
import { audio_element } from './audio-element';
|
||||||
|
|
||||||
$: $audio_element;
|
$: $audio_element;
|
||||||
/* onMount(() => {
|
/* onMount(() => {
|
||||||
@@ -22,3 +22,96 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<svelte:head>
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--svpod--font: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
|
||||||
|
'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
|
||||||
|
'Segoe UI Symbol', 'Noto Color Emoji';
|
||||||
|
|
||||||
|
--svpod--surface--darker: rgb(0, 0, 0);
|
||||||
|
--svpod--surface--base: rgb(40, 40, 40);
|
||||||
|
--svpod--surface--lighter: rgb(60, 60, 60);
|
||||||
|
|
||||||
|
--svpod--content--darker: rgb(150, 150, 150);
|
||||||
|
--svpod--content--base: rgb(200, 200, 200);
|
||||||
|
--svpod--content--lighter: rgb(255, 255, 255);
|
||||||
|
|
||||||
|
--svpod--accent--darker: rgb(75, 15, 0);
|
||||||
|
--svpod--accent--base: rgb(180, 40, 0);
|
||||||
|
--svpod--accent--lighter: rgb(255, 55, 25);
|
||||||
|
|
||||||
|
--bg: var(--svpod--surface--darker);
|
||||||
|
--fg: var(--svpod--content--darker);
|
||||||
|
|
||||||
|
--svpod--radius--rounded: 9999px;
|
||||||
|
|
||||||
|
/* element : timeline */
|
||||||
|
|
||||||
|
--svpod--timeline-track--shape--height: 20px;
|
||||||
|
--svpod--timeline-track--shape--radius: 0;
|
||||||
|
--svpod--timeline-track--shape--border: 0;
|
||||||
|
|
||||||
|
--svpod--timeline-thumb--shape--width: 8px;
|
||||||
|
--svpod--timeline-thumb--shape--height: 32px;
|
||||||
|
--svpod--timeline-thumb--shape--radius: 6px;
|
||||||
|
--svpod--timeline-thumb--shape--border: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.svpod--reset {
|
||||||
|
text-transform: none;
|
||||||
|
font-style: normal;
|
||||||
|
text-indent: 0;
|
||||||
|
text-shadow: none;
|
||||||
|
text-align: left;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.svpod--a11y-hidden {
|
||||||
|
position: absolute;
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
padding: 0;
|
||||||
|
margin: -1px;
|
||||||
|
overflow: hidden;
|
||||||
|
clip: rect(0, 0, 0, 0);
|
||||||
|
white-space: nowrap;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.svpod--button,
|
||||||
|
.svpod--icon-button {
|
||||||
|
--fg: var(--svpod--content--base);
|
||||||
|
--bg: var(--svpod--surface--base);
|
||||||
|
position: relative;
|
||||||
|
line-height: 1em;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 8px;
|
||||||
|
font-size: 16px;
|
||||||
|
border: 0px solid transparent;
|
||||||
|
border-radius: var(--svpod--radius--rounded);
|
||||||
|
background-color: var(--bg);
|
||||||
|
color: var(--fg);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.svpod--button:hover,
|
||||||
|
.svpod--icon-button:hover {
|
||||||
|
--fg: var(--svpod--content--lighter);
|
||||||
|
--bg: var(--svpod--surface--lighter);
|
||||||
|
}
|
||||||
|
|
||||||
|
.svpod--button {
|
||||||
|
padding: 4px calc(1em);
|
||||||
|
}
|
||||||
|
|
||||||
|
.svpod--icon-button {
|
||||||
|
padding: 8px;
|
||||||
|
min-width: 48px;
|
||||||
|
min-height: 48px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</svelte:head>
|
||||||
|
|||||||
@@ -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 clamp from 'just-clamp';
|
||||||
import { derived, get, type Readable } from 'svelte/store';
|
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 = {
|
const default_episode_attributes = {
|
||||||
will_autoplay: false,
|
will_autoplay: false,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { EpisodeDetails } from '$lib/types';
|
|
||||||
import { writable } from 'svelte/store';
|
import { writable } from 'svelte/store';
|
||||||
|
import type { EpisodeDetails } from '../types';
|
||||||
|
|
||||||
export const episode_details = writable<EpisodeDetails | null>(null);
|
export const episode_details = writable<EpisodeDetails | null>(null);
|
||||||
|
|||||||
@@ -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 { 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 = {
|
const default_episode_progress = {
|
||||||
current_time: 0,
|
current_time: 0,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
export { default as AudioLoader } from '$lib/audio/audio-loader.svelte';
|
export { default as AudioLoader } from './audio-loader.svelte';
|
||||||
export * from '$lib/audio/episode-data';
|
export * from './episode-data';
|
||||||
export * from '$lib/audio/episode-details';
|
export * from './episode-details';
|
||||||
export * from '$lib/audio/episode-progress';
|
export * from './episode-progress';
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
export let currentTime: number;
|
|
||||||
export let paused: boolean;
|
|
||||||
export let duration: number;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<progress data-paused={paused ? 'true' : 'false'} max={duration} value={currentTime} />
|
|
||||||
|
|
||||||
<style>
|
|
||||||
progress {
|
|
||||||
position: absolute;
|
|
||||||
width: 1px;
|
|
||||||
height: 1px;
|
|
||||||
padding: 0;
|
|
||||||
margin: -1px;
|
|
||||||
overflow: hidden;
|
|
||||||
clip: rect(0, 0, 0, 0);
|
|
||||||
white-space: nowrap;
|
|
||||||
border: 0;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -0,0 +1,145 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { episode_audio, episode_progress } from '../audio';
|
||||||
|
import { info } from '../utility/package/log';
|
||||||
|
|
||||||
|
export let step = 10;
|
||||||
|
|
||||||
|
let was_paused = true;
|
||||||
|
|
||||||
|
function handle_drag_start(t: string) {
|
||||||
|
info('drag_start :: ', t);
|
||||||
|
was_paused = $episode_audio?.is_paused || true;
|
||||||
|
episode_audio.pause();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handle_drag_end(t: string) {
|
||||||
|
info('drag_end :: ', t);
|
||||||
|
if (was_paused) return;
|
||||||
|
else episode_audio.play();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
input[type='range'] {
|
||||||
|
--track--shape--height: calc(var(--svpod--timeline-track--shape--height));
|
||||||
|
--thumb-border-offset: calc(var(--svpod--timeline-thumb--shape--border) * 2);
|
||||||
|
--thumb--shape--height: calc(
|
||||||
|
var(--svpod--timeline-thumb--shape--height) - var(--thumb-border-offset)
|
||||||
|
);
|
||||||
|
|
||||||
|
--svpod--timeline-track--bg: var(--svpod--surface--base);
|
||||||
|
--svpod--timeline-track--border: var(--bg);
|
||||||
|
|
||||||
|
--svpod--timeline-thumb--bg: var(--svpod--content--base);
|
||||||
|
--svpod--timeline-thumb--border: var(--bg);
|
||||||
|
|
||||||
|
font-size: 1em;
|
||||||
|
|
||||||
|
--borders: calc(var(--svpod--timeline-thumb--shape--border) * 2);
|
||||||
|
--no-shadow: 0px 0px 0px transparent;
|
||||||
|
|
||||||
|
height: calc(var(--thumb--shape--height) + var(--borders));
|
||||||
|
appearance: none;
|
||||||
|
margin: 0;
|
||||||
|
width: 100%;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
input[type='range']:hover {
|
||||||
|
--svpod--timeline-track--bg: var(--svpod--accent--darker);
|
||||||
|
--svpod--timeline-track--border: var(--svpod--accent--base);
|
||||||
|
--svpod--timeline-thumb--bg: var(--svpod--accent--lighter);
|
||||||
|
}
|
||||||
|
input[type='range']:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
input[type='range']::-webkit-slider-runnable-track {
|
||||||
|
width: 100%;
|
||||||
|
height: var(--track--shape--height);
|
||||||
|
cursor: pointer;
|
||||||
|
animate: 0.2s;
|
||||||
|
box-shadow: var(--no-shadow);
|
||||||
|
background: var(--svpod--timeline-track--bg);
|
||||||
|
border-radius: var(--svpod--timeline-track--shape--radius);
|
||||||
|
border: var(--svpod--timeline-track--shape--border) solid var(--svpod--timeline-track--border);
|
||||||
|
}
|
||||||
|
input[type='range']::-webkit-slider-thumb {
|
||||||
|
--offset: calc(var(--svpod--timeline-track--shape--border) * -1);
|
||||||
|
box-shadow: var(--no-shadow);
|
||||||
|
border: var(--svpod--timeline-thumb--shape--border) solid var(--svpod--timeline-thumb--border);
|
||||||
|
height: var(--thumb--shape--height);
|
||||||
|
width: var(--svpod--timeline-thumb--shape--width);
|
||||||
|
border-radius: var(--svpod--timeline-thumb--shape--radius);
|
||||||
|
background: var(--svpod--timeline-thumb--bg);
|
||||||
|
cursor: pointer;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
margin-top: var(--offset);
|
||||||
|
}
|
||||||
|
input[type='range']:focus::-webkit-slider-runnable-track {
|
||||||
|
background: var(--svpod--timeline-track--bg);
|
||||||
|
}
|
||||||
|
input[type='range']::-moz-range-track {
|
||||||
|
width: 100%;
|
||||||
|
height: var(--track--shape--height);
|
||||||
|
cursor: pointer;
|
||||||
|
animate: 0.2s;
|
||||||
|
box-shadow: var(--no-shadow);
|
||||||
|
background: var(--svpod--timeline-track--bg);
|
||||||
|
border-radius: var(--svpod--timeline-track--shape--radius);
|
||||||
|
border: var(--svpod--timeline-track--shape--border) solid var(--svpod--timeline-track--border);
|
||||||
|
}
|
||||||
|
input[type='range']::-moz-range-thumb {
|
||||||
|
box-shadow: var(--no-shadow);
|
||||||
|
border: var(--svpod--timeline-thumb--shape--border) solid var(--svpod--timeline-thumb--border);
|
||||||
|
height: var(--thumb--shape--height);
|
||||||
|
width: var(--svpod--timeline-thumb--shape--width);
|
||||||
|
border-radius: var(--svpod--timeline-thumb--shape--radius);
|
||||||
|
background: var(--svpod--timeline-thumb--bg);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
input[type='range']::-ms-track {
|
||||||
|
width: 100%;
|
||||||
|
height: var(--track--shape--height);
|
||||||
|
cursor: pointer;
|
||||||
|
animate: 0.2s;
|
||||||
|
background: transparent;
|
||||||
|
border-color: transparent;
|
||||||
|
color: transparent;
|
||||||
|
}
|
||||||
|
input[type='range']::-ms-fill-lower,
|
||||||
|
input[type='range']::-ms-fill-upper {
|
||||||
|
background: var(--svpod--timeline-track--bg);
|
||||||
|
border: var(--svpod--timeline-track--shape--border) solid var(--svpod--timeline-track--border);
|
||||||
|
border-radius: calc(var(--svpod--timeline-track--shape--radius) * 2);
|
||||||
|
box-shadow: var(--no-shadow);
|
||||||
|
}
|
||||||
|
input[type='range']::-ms-thumb {
|
||||||
|
margin-top: 1px;
|
||||||
|
box-shadow: var(--no-shadow);
|
||||||
|
border: var(--svpod--timeline-thumb--shape--border) solid var(--svpod--timeline-thumb--border);
|
||||||
|
height: var(--thumb--shape--height);
|
||||||
|
width: var(--svpod--timeline-thumb--shape--width);
|
||||||
|
border-radius: var(--svpod--timeline-thumb--shape--radius);
|
||||||
|
background: var(--svpod--timeline-thumb--bg);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
input[type='range']:focus::-ms-fill-lower,
|
||||||
|
input[type='range']:focus::-ms-fill-upper {
|
||||||
|
background: var(--svpod--timeline-track--bg);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<input
|
||||||
|
class={$$props.class}
|
||||||
|
style="display:block; width:100%;"
|
||||||
|
type="range"
|
||||||
|
data-paused={$episode_audio?.is_paused ? 'true' : 'false'}
|
||||||
|
min={0}
|
||||||
|
{step}
|
||||||
|
max={$episode_audio?.duration || step}
|
||||||
|
value={$episode_progress.current_time}
|
||||||
|
on:change={(e) => 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')}
|
||||||
|
/>
|
||||||
@@ -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';
|
||||||
@@ -0,0 +1,318 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Pause, Play, SpeakerWave } from '@inqling/svelte-icons/heroicon-20-solid';
|
||||||
|
import { clsx } from 'clsx';
|
||||||
|
import { HeadlessTimeline } from '.';
|
||||||
|
import { episode_audio, episode_progress } from '../audio';
|
||||||
|
import { user_preferences } from '../user';
|
||||||
|
import { A11yIcon, Skip, Spinner, Timestamp } from './utility';
|
||||||
|
|
||||||
|
type WithElement = {
|
||||||
|
timestamps: boolean;
|
||||||
|
playback_rate: boolean;
|
||||||
|
skip_back: number;
|
||||||
|
skip_forward: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
const default_options = {
|
||||||
|
timestamps: false,
|
||||||
|
playback_rate: false,
|
||||||
|
skip_back: 10,
|
||||||
|
skip_forward: 10,
|
||||||
|
} satisfies WithElement;
|
||||||
|
|
||||||
|
export let include: Partial<WithElement> = {};
|
||||||
|
$: options = { ...default_options, ...include };
|
||||||
|
|
||||||
|
$: is_playing = $episode_audio?.is_paused === false;
|
||||||
|
|
||||||
|
$: timestamp_hours = Boolean($episode_audio?.duration && $episode_audio.duration >= 3600);
|
||||||
|
|
||||||
|
export let playback_rate_values: number[] = [1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4];
|
||||||
|
|
||||||
|
$: is_loaded = Boolean($episode_audio?.src);
|
||||||
|
|
||||||
|
const { class: ClassName, ...rest } = $$restProps;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.svpod--container {
|
||||||
|
--fg: var(--svpod--content--base);
|
||||||
|
--bg: var(--svpod--surface--darker);
|
||||||
|
|
||||||
|
--padding: 2px;
|
||||||
|
--radius: 0.75em;
|
||||||
|
--inner-radius: calc(var(--radius) - var(--padding));
|
||||||
|
|
||||||
|
--svpod--timeline-track--shape--height: 3em;
|
||||||
|
--svpod--timeline-track--shape--radius: var(--inner-radius);
|
||||||
|
--svpod--timeline-track--shape--border: 2px;
|
||||||
|
|
||||||
|
--svpod--timeline-thumb--shape--height: var(--svpod--timeline-track--shape--height);
|
||||||
|
--svpod--timeline-thumb--shape--width: 3px;
|
||||||
|
--svpod--timeline-thumb--shape--radius: 1px;
|
||||||
|
--svpod--timeline-thumb--shape--border: 0px;
|
||||||
|
|
||||||
|
background-color: var(--bg);
|
||||||
|
color: var(--fg);
|
||||||
|
display: inline-flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1em;
|
||||||
|
width: auto;
|
||||||
|
max-width: 100%;
|
||||||
|
border-radius: var(--radius);
|
||||||
|
font-weight: 600;
|
||||||
|
padding: var(--padding);
|
||||||
|
gap: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.svpod--container--row {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: stretch;
|
||||||
|
justify-content: flex-end;
|
||||||
|
width: 100%;
|
||||||
|
min-width: max-content;
|
||||||
|
border-radius: var(--inner-radius);
|
||||||
|
gap: var(--padding);
|
||||||
|
}
|
||||||
|
.svpod--container--row:last-child {
|
||||||
|
border-top: 1px solid var(--svpod--surface--base);
|
||||||
|
border-top-right-radius: 0;
|
||||||
|
border-top-left-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.svpod--row--artwork {
|
||||||
|
order: 0;
|
||||||
|
}
|
||||||
|
.svpod--row--timeline {
|
||||||
|
order: 1;
|
||||||
|
}
|
||||||
|
.svpod--row--controls {
|
||||||
|
order: 2;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.svpod--row--timestamps {
|
||||||
|
order: 3;
|
||||||
|
min-height: 32px;
|
||||||
|
gap: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.svpod--timeline {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: stretch;
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-shrink: 1;
|
||||||
|
font-size: 1em;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.svpod--toggle-pause {
|
||||||
|
align-items: center;
|
||||||
|
border: none;
|
||||||
|
display: flex;
|
||||||
|
font-size: 1em;
|
||||||
|
height: 3em;
|
||||||
|
justify-content: center;
|
||||||
|
width: 3em;
|
||||||
|
border-radius: var(--inner-radius);
|
||||||
|
}
|
||||||
|
button.svpod--toggle-pause {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.svpod--toggle-pause :global(svg) {
|
||||||
|
width: 1.5em;
|
||||||
|
height: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.svpod--timestamp {
|
||||||
|
background-color: var(--bg);
|
||||||
|
display: inline-flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 4px;
|
||||||
|
font-size: 1em;
|
||||||
|
line-height: 1em;
|
||||||
|
pointer-events: none;
|
||||||
|
border-radius: var(--inner-radius);
|
||||||
|
width: max-content;
|
||||||
|
flex-grow: 0;
|
||||||
|
text-align: center;
|
||||||
|
padding: 0 0.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
select.svpod--playback-rate {
|
||||||
|
background-color: var(--bg);
|
||||||
|
appearance: none;
|
||||||
|
padding: 0 0.75em;
|
||||||
|
color: var(--fg);
|
||||||
|
overflow: hidden;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
font-size: 0.8em;
|
||||||
|
line-height: 1em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-weight: 600;
|
||||||
|
text-align: center;
|
||||||
|
min-width: 48px;
|
||||||
|
outline-color: var(--svpod--accent--lighter);
|
||||||
|
cursor: pointer;
|
||||||
|
margin: 0;
|
||||||
|
border-radius: var(--inner-radius);
|
||||||
|
}
|
||||||
|
select.svpod--playback-rate,
|
||||||
|
select.svpod--playback-rate:hover,
|
||||||
|
select.svpod--playback-rate:focus {
|
||||||
|
border: none;
|
||||||
|
shadow: none;
|
||||||
|
}
|
||||||
|
select.svpod--playback-rate:focus {
|
||||||
|
--fg: var(--svpod--accent--lighter);
|
||||||
|
}
|
||||||
|
|
||||||
|
button.svpod--toggle-pause,
|
||||||
|
select.svpod--playback-rate {
|
||||||
|
background-color: var(--bg);
|
||||||
|
color: var(--fg);
|
||||||
|
}
|
||||||
|
button.svpod--toggle-pause:hover,
|
||||||
|
select.svpod--playback-rate:hover {
|
||||||
|
--bg: var(--svpod--surface--base);
|
||||||
|
--fg: var(--svpod--content--lighter);
|
||||||
|
background-color: var(--bg);
|
||||||
|
color: var(--fg);
|
||||||
|
}
|
||||||
|
div.svpod--artwork {
|
||||||
|
position: relative;
|
||||||
|
border-radius: var(--inner-radius);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
div.svpod--artwork > :global(div),
|
||||||
|
div.svpod--artwork > :global(img) {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
.svpod--artwork--placeholder {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: var(--svpod--accent--lighter);
|
||||||
|
font-size: 2.5em;
|
||||||
|
}
|
||||||
|
.svpod--artwork--placeholder :global(svg) {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
.svpod--artwork--placeholder::after {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
content: '';
|
||||||
|
opacity: 0.5;
|
||||||
|
background: linear-gradient(45deg, var(--svpod--accent--base), transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
span.svpod--aspect--square {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
line-height: 0;
|
||||||
|
padding-bottom: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class={clsx('svpod--container svpod--reset', ClassName)}
|
||||||
|
data-loaded={is_loaded ? 'true' : 'false'}
|
||||||
|
{...rest}
|
||||||
|
>
|
||||||
|
<div class="svpod--container--row svpod--row--controls">
|
||||||
|
<button
|
||||||
|
on:click={() => options.skip_back && episode_audio.skip(options.skip_back, 'backward')}
|
||||||
|
class="svpod--reset svpod--toggle-pause"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<Skip value={options.skip_back} type="backward" />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- toggle play -->
|
||||||
|
{#if is_loaded}
|
||||||
|
<button
|
||||||
|
on:click={() => is_loaded && episode_audio.play('toggle')}
|
||||||
|
class="svpod--reset svpod--toggle-pause"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<A11yIcon icon={is_playing ? Pause : Play} label={is_playing ? 'Pause' : 'Play'} />
|
||||||
|
</button>
|
||||||
|
{:else}
|
||||||
|
<div class="svpod--reset svpod--toggle-pause">
|
||||||
|
<A11yIcon icon={Spinner} label="Waiting for audio..." />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<button
|
||||||
|
on:click={() => options.skip_forward && episode_audio.skip(options.skip_forward, 'forward')}
|
||||||
|
class="svpod--reset svpod--toggle-pause"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<Skip value={options.skip_forward} type="forward" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="svpod--artwork svpod--row--artwork">
|
||||||
|
<span class="svpod--aspect--square" />
|
||||||
|
<slot>
|
||||||
|
<div class="svpod--artwork--placeholder">
|
||||||
|
<span><SpeakerWave style="width:1em; height: 1em;" /></span>
|
||||||
|
</div>
|
||||||
|
</slot>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="svpod--timeline svpod--row--timeline">
|
||||||
|
<HeadlessTimeline />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if options.timestamps || options.playback_rate}
|
||||||
|
<div class="svpod--container--row svpod--row--timestamps">
|
||||||
|
{#if options.timestamps}
|
||||||
|
<div class="svpod--timestamp">
|
||||||
|
<Timestamp value={$episode_progress?.current_time || 0} force_hours={timestamp_hours} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="flex-grow: 1" />
|
||||||
|
|
||||||
|
<div class="svpod--timestamp">
|
||||||
|
<Timestamp value={$episode_audio?.duration || 0} />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if options.playback_rate}
|
||||||
|
<select
|
||||||
|
class="svpod--playback-rate"
|
||||||
|
value={$user_preferences.playback_rate}
|
||||||
|
on:change={(e) => {
|
||||||
|
const value = parseFloat(e.currentTarget.value);
|
||||||
|
user_preferences.set.playback_rate(value);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{#each playback_rate_values as value}
|
||||||
|
<option {value}>
|
||||||
|
{#if Number.isInteger(value)}
|
||||||
|
{value}.0
|
||||||
|
{:else}
|
||||||
|
{value}
|
||||||
|
{/if}
|
||||||
|
</option>
|
||||||
|
{/each}
|
||||||
|
</select>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,234 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Pause, Play } from '@inqling/svelte-icons/heroicon-20-solid';
|
||||||
|
import { clsx } from 'clsx';
|
||||||
|
import { HeadlessTimeline } from '.';
|
||||||
|
import { episode_audio, episode_progress } from '../audio';
|
||||||
|
import { user_preferences } from '../user';
|
||||||
|
import { A11yIcon, Skip, Spinner, Timestamp } from './utility';
|
||||||
|
|
||||||
|
type WithElement = {
|
||||||
|
duration: boolean;
|
||||||
|
current_time: boolean;
|
||||||
|
playback_rate: boolean;
|
||||||
|
skip_back: number | null;
|
||||||
|
skip_forward: number | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const default_options = {
|
||||||
|
duration: false,
|
||||||
|
current_time: false,
|
||||||
|
playback_rate: false,
|
||||||
|
skip_back: null,
|
||||||
|
skip_forward: null,
|
||||||
|
} satisfies WithElement;
|
||||||
|
|
||||||
|
export let include: Partial<WithElement> = {};
|
||||||
|
$: options = { ...default_options, ...include };
|
||||||
|
|
||||||
|
$: is_playing = $episode_audio?.is_paused === false;
|
||||||
|
|
||||||
|
$: current_time = options.current_time && ($episode_progress?.current_time || 0);
|
||||||
|
$: duration = options.duration && ($episode_audio?.duration || 0);
|
||||||
|
$: timestamp_hours = Boolean($episode_audio?.duration && $episode_audio.duration >= 3600);
|
||||||
|
|
||||||
|
export let playback_rate_values: number[] = [1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4];
|
||||||
|
|
||||||
|
$: is_loaded = Boolean($episode_audio?.src);
|
||||||
|
|
||||||
|
const { class: ClassName, ...rest } = $$restProps;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.svpod--container {
|
||||||
|
--fg: var(--svpod--content--base);
|
||||||
|
--bg: var(--svpod--surface--darker);
|
||||||
|
|
||||||
|
--padding: 2px;
|
||||||
|
--radius: 0.5em;
|
||||||
|
--inner-radius: calc(var(--radius) - var(--padding));
|
||||||
|
|
||||||
|
--svpod--timeline-track--shape--height: 3em;
|
||||||
|
--svpod--timeline-track--shape--radius: var(--inner-radius);
|
||||||
|
--svpod--timeline-track--shape--border: 2px;
|
||||||
|
|
||||||
|
--svpod--timeline-thumb--shape--height: var(--svpod--timeline-track--shape--height);
|
||||||
|
--svpod--timeline-thumb--shape--width: 3px;
|
||||||
|
--svpod--timeline-thumb--shape--radius: 1px;
|
||||||
|
--svpod--timeline-thumb--shape--border: 0px;
|
||||||
|
|
||||||
|
background-color: var(--bg);
|
||||||
|
color: var(--fg);
|
||||||
|
display: inline-flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: stretch;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1em;
|
||||||
|
min-width: 320px;
|
||||||
|
max-width: 100%;
|
||||||
|
border-radius: var(--radius);
|
||||||
|
font-weight: 600;
|
||||||
|
padding: var(--padding);
|
||||||
|
gap: var(--padding);
|
||||||
|
}
|
||||||
|
|
||||||
|
div.svpod--timeline {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: stretch;
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-shrink: 1;
|
||||||
|
font-size: 1em;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.svpod--toggle-pause {
|
||||||
|
align-items: center;
|
||||||
|
border: none;
|
||||||
|
display: flex;
|
||||||
|
font-size: 1em;
|
||||||
|
height: 3em;
|
||||||
|
justify-content: center;
|
||||||
|
width: 3em;
|
||||||
|
border-radius: var(--inner-radius);
|
||||||
|
}
|
||||||
|
button.svpod--toggle-pause {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.svpod--toggle-pause :global(svg) {
|
||||||
|
width: 1.5em;
|
||||||
|
height: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.svpod--timestamp {
|
||||||
|
background-color: var(--bg);
|
||||||
|
display: inline-flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 4px;
|
||||||
|
font-size: 1em;
|
||||||
|
line-height: 1em;
|
||||||
|
pointer-events: none;
|
||||||
|
border-radius: var(--inner-radius);
|
||||||
|
width: max-content;
|
||||||
|
flex-grow: 0;
|
||||||
|
text-align: center;
|
||||||
|
padding: 0 0.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
select.svpod--playback-rate {
|
||||||
|
background-color: var(--bg);
|
||||||
|
appearance: none;
|
||||||
|
padding: 0 0.75em;
|
||||||
|
color: var(--fg);
|
||||||
|
overflow: hidden;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
font-size: 0.8em;
|
||||||
|
line-height: 1em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-weight: 600;
|
||||||
|
text-align: center;
|
||||||
|
min-width: 48px;
|
||||||
|
outline-color: var(--svpod--accent--lighter);
|
||||||
|
cursor: pointer;
|
||||||
|
margin: 0;
|
||||||
|
border-radius: var(--inner-radius);
|
||||||
|
}
|
||||||
|
select.svpod--playback-rate,
|
||||||
|
select.svpod--playback-rate:hover,
|
||||||
|
select.svpod--playback-rate:focus {
|
||||||
|
border: none;
|
||||||
|
shadow: none;
|
||||||
|
}
|
||||||
|
select.svpod--playback-rate:focus {
|
||||||
|
--fg: var(--svpod--accent--lighter);
|
||||||
|
}
|
||||||
|
|
||||||
|
button.svpod--toggle-pause,
|
||||||
|
select.svpod--playback-rate {
|
||||||
|
background-color: var(--bg);
|
||||||
|
color: var(--fg);
|
||||||
|
}
|
||||||
|
button.svpod--toggle-pause:hover,
|
||||||
|
select.svpod--playback-rate:hover {
|
||||||
|
--bg: var(--svpod--surface--base);
|
||||||
|
--fg: var(--svpod--content--lighter);
|
||||||
|
background-color: var(--bg);
|
||||||
|
color: var(--fg);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class={clsx('svpod--container svpod--reset', ClassName)}
|
||||||
|
data-loaded={is_loaded ? 'true' : 'false'}
|
||||||
|
{...rest}
|
||||||
|
>
|
||||||
|
{#if options.skip_back}
|
||||||
|
<button
|
||||||
|
on:click={() => options.skip_back && episode_audio.skip(options.skip_back, 'backward')}
|
||||||
|
class="svpod--reset svpod--toggle-pause"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<Skip value={options.skip_back} type="backward" />
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<!-- toggle play -->
|
||||||
|
{#if is_loaded}
|
||||||
|
<button
|
||||||
|
on:click={() => is_loaded && episode_audio.play('toggle')}
|
||||||
|
class="svpod--reset svpod--toggle-pause"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<A11yIcon icon={is_playing ? Pause : Play} label={is_playing ? 'Pause' : 'Play'} />
|
||||||
|
</button>
|
||||||
|
{:else}
|
||||||
|
<div class="svpod--reset svpod--toggle-pause">
|
||||||
|
<A11yIcon icon={Spinner} label="Waiting for audio..." />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if options.skip_forward}
|
||||||
|
<button
|
||||||
|
on:click={() => options.skip_forward && episode_audio.skip(options.skip_forward, 'forward')}
|
||||||
|
class="svpod--reset svpod--toggle-pause"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<Skip value={options.skip_forward} type="forward" />
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if current_time !== false}
|
||||||
|
<div class="svpod--timestamp">
|
||||||
|
<Timestamp value={current_time} force_hours={timestamp_hours} />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
<div class="svpod--timeline">
|
||||||
|
<HeadlessTimeline />
|
||||||
|
</div>
|
||||||
|
{#if duration !== false}
|
||||||
|
<div class="svpod--timestamp">
|
||||||
|
<Timestamp value={duration} />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{#if options.playback_rate}
|
||||||
|
<select
|
||||||
|
class="svpod--playback-rate"
|
||||||
|
value={$user_preferences.playback_rate}
|
||||||
|
on:change={(e) => {
|
||||||
|
const value = parseFloat(e.currentTarget.value);
|
||||||
|
user_preferences.set.playback_rate(value);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{#each playback_rate_values as value}
|
||||||
|
<option {value}>
|
||||||
|
{#if Number.isInteger(value)}
|
||||||
|
{value}.0
|
||||||
|
{:else}
|
||||||
|
{value}
|
||||||
|
{/if}
|
||||||
|
</option>
|
||||||
|
{/each}
|
||||||
|
</select>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { SvelteIcon } from '@inqling/svelte-icons';
|
||||||
|
|
||||||
|
export let icon: SvelteIcon;
|
||||||
|
export let label: string;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:component this={icon} />
|
||||||
|
<span class="svpod--a11y-hidden">{label}</span>
|
||||||
@@ -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';
|
||||||
@@ -0,0 +1,155 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
export let size = 24;
|
||||||
|
export let value: number;
|
||||||
|
export let type: 'forward' | 'backward';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
div.svpod--skip-container {
|
||||||
|
display: inline-flex;
|
||||||
|
position: relative;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 1.5em;
|
||||||
|
height: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.svpod--skip-icon,
|
||||||
|
span.svpod--skip-mask {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.svpod--skip-mask {
|
||||||
|
z-index: 1;
|
||||||
|
background: linear-gradient(0deg, var(--bg), transparent);
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.svpod--skip-icon {
|
||||||
|
z-index: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: var(--svpod--content--base);
|
||||||
|
}
|
||||||
|
|
||||||
|
span.svpod--skip-label {
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
font-size: 0.5em;
|
||||||
|
line-height: 1em;
|
||||||
|
color: var(--svpod--content--lighter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes Spin {
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
/* animation: Spin 1s cubic-bezier(0.5, 0.1, 0.1, 0.8) infinite; */
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="svpod--skip-container" style="font-size:{size}px">
|
||||||
|
<span class="svpod--skip-label">
|
||||||
|
<span class="svpod--a11y-hidden">skip {type}</span>
|
||||||
|
{value}
|
||||||
|
<span class="svpod--a11y-hidden">seconds</span>
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
class="svpod--skip-mask"
|
||||||
|
class:svpod--skip-mask--right={type === 'backward'}
|
||||||
|
class:svpod--skip-mask--left={type === 'backward'}
|
||||||
|
/>
|
||||||
|
<div class="svpod--skip-icon">
|
||||||
|
{#if type === 'forward'}
|
||||||
|
<!-- forward -->
|
||||||
|
<svg
|
||||||
|
width={size}
|
||||||
|
height={size}
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
style="font-size:{size}px"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M15.5922 0.913446C14.1363 0.310389 12.5759 -1.8792e-08 11 0L11 2C12.3132 2 13.6136 2.25866 14.8268 2.7612C16.0401 3.26375 17.1425 4.00035 18.0711 4.92893C18.9997 5.85752 19.7362 6.95991 20.2388 8.17317C20.6133 9.07731 20.8524 10.0298 20.9499 11H22.9583C22.8551 9.76677 22.5617 8.55484 22.0866 7.4078C21.4835 5.95189 20.5996 4.62902 19.4853 3.51472C18.371 2.40042 17.0481 1.5165 15.5922 0.913446Z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M22.9583 13C22.9338 13.2923 22.8987 13.5835 22.853 13.8728L20.9082 13.3517C20.9242 13.2348 20.9381 13.1175 20.9499 13H22.9583Z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M20.4408 15.297L22.3771 15.8159C22.2894 16.0775 22.1925 16.3365 22.0866 16.5922C22.078 16.6128 22.0694 16.6334 22.0608 16.6539L20.3123 15.6444C20.3573 15.5293 20.4002 15.4135 20.4408 15.297Z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M19.3994 17.4268L21.1333 18.4278C20.9675 18.6892 20.7916 18.944 20.6061 19.1919L19.1744 17.7602C19.2516 17.6505 19.3267 17.5394 19.3994 17.4268Z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M17.8609 19.2751L19.2757 20.6899C19.0399 20.9144 18.7954 21.1289 18.5429 21.333L17.5281 19.5752C17.6412 19.4778 17.7521 19.3777 17.8609 19.2751Z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M15.8834 20.7265L16.8835 22.4587C16.5838 22.6273 16.2766 22.7831 15.9628 22.9257L15.4366 20.9619C15.5876 20.8872 15.7366 20.8087 15.8834 20.7265Z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M13.5553 21.668L14.0729 23.5999C13.7189 23.6937 13.3609 23.7712 13 23.8322V21.798C13.1862 21.7599 13.3714 21.7166 13.5553 21.668Z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
{:else}
|
||||||
|
<!-- back -->
|
||||||
|
<svg
|
||||||
|
width={size}
|
||||||
|
height={size}
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
style="font-size:{size}px"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M11.0003 21.9499V23.9583C10.6215 23.9266 10.2447 23.877 9.87115 23.8096L10.391 21.8697C10.5931 21.9026 10.7963 21.9294 11.0003 21.9499Z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M7.8915 21.1169C7.98478 21.159 8.07876 21.1996 8.17342 21.2388C8.26813 21.278 8.36337 21.3158 8.45911 21.352L7.9393 23.292C7.7608 23.2278 7.58367 23.1593 7.40805 23.0866C7.23249 23.0138 7.05886 22.937 6.8873 22.8562L7.8915 21.1169Z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M5.67173 19.7427C5.8305 19.8725 5.99315 19.9973 6.15943 20.1169L5.15524 21.8563C4.84345 21.6397 4.54188 21.4084 4.25159 21.1629L5.67173 19.7427Z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M3.88341 17.841C4.00303 18.0072 4.12778 18.1698 4.25752 18.3285L2.83737 19.7487C2.59192 19.4584 2.36059 19.1569 2.14409 18.8452L3.88341 17.841Z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M2.64825 15.5412C2.68449 15.6369 2.72223 15.7321 2.76146 15.8268C2.80069 15.9215 2.84134 16.0156 2.88341 16.1089L1.14409 17.1131C1.06327 16.9415 0.986441 16.7678 0.913699 16.5922C0.840963 16.4166 0.772485 16.2395 0.708295 16.061L2.64825 15.5412Z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M2.05038 13C2.07088 13.204 2.09764 13.4072 2.1306 13.6093L0.19065 14.1291C0.123306 13.7556 0.0736704 13.3788 0.0419922 13H2.05038Z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M2.05038 11C2.14788 10.0298 2.38695 9.07731 2.76146 8.17317C3.26401 6.95991 4.0006 5.85752 4.92919 4.92893C5.85777 4.00035 6.96016 3.26375 8.17342 2.7612C9.38667 2.25866 10.687 2 12.0003 2V0C10.4244 1.8792e-08 8.86396 0.310389 7.40805 0.913446C5.95215 1.5165 4.62928 2.40042 3.51497 3.51472C2.40067 4.62902 1.51676 5.95189 0.913699 7.4078C0.438578 8.55484 0.145121 9.76677 0.0419922 11H2.05038Z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
export let size = 24;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
div.svpod--spinner-container {
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.svpod--item {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
opacity: 0.5;
|
||||||
|
color: var(--svpod--accent--lighter);
|
||||||
|
}
|
||||||
|
div.svpod--item:nth-child(1) {
|
||||||
|
opacity: 1;
|
||||||
|
color: var(--svpod--content--lighter);
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes Spin {
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
animation: Spin 1s cubic-bezier(0.5, 0.1, 0.1, 0.8) infinite;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="svpod--spinner-container" style="width:{size}px; height:{size}px">
|
||||||
|
{#each [0, 0.075, 0.15] as delay}
|
||||||
|
<div class="svpod--item">
|
||||||
|
<svg
|
||||||
|
width={size}
|
||||||
|
height={size}
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
style="animation-delay: {delay}s;"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M24 12C24 14.3734 23.2962 16.6935 21.9776 18.6668C20.6591 20.6402 18.7849 22.1783 16.5922 23.0866C14.3995 23.9948 11.9867 24.2324 9.65892 23.7694C7.33114 23.3064 5.19295 22.1635 3.51472 20.4853C1.83649 18.8071 0.693599 16.6689 0.230577 14.3411C-0.232446 12.0133 0.00519403 9.60051 0.913446 7.4078C1.8217 5.21509 3.35977 3.34094 5.33316 2.02236C7.30655 0.703788 9.62662 -2.83022e-08 12 0L12 3C10.22 3 8.47991 3.52784 6.99987 4.51677C5.51983 5.50571 4.36627 6.91131 3.68508 8.55585C3.0039 10.2004 2.82567 12.01 3.17293 13.7558C3.5202 15.5016 4.37737 17.1053 5.63604 18.364C6.89471 19.6226 8.49836 20.4798 10.2442 20.8271C11.99 21.1743 13.7996 20.9961 15.4442 20.3149C17.0887 19.6337 18.4943 18.4802 19.4832 17.0001C20.4722 15.5201 21 13.78 21 12H24Z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { secondsToTimestamp } from '../../utility';
|
||||||
|
|
||||||
|
export let value: number;
|
||||||
|
export let force_hours = false;
|
||||||
|
|
||||||
|
$: timestamp = secondsToTimestamp(value, force_hours);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
span {
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
font-size: 0.8em;
|
||||||
|
display: block;
|
||||||
|
width: 8ch;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<span style="width:{timestamp.length}ch">{timestamp}</span>
|
||||||
+4
-3
@@ -1,3 +1,4 @@
|
|||||||
export * from '$lib/audio';
|
export * from './audio';
|
||||||
export * from '$lib/user';
|
export * from './components';
|
||||||
export * from '$lib/utility';
|
export * from './user';
|
||||||
|
export * from './utility';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { UserPreferences } from '$lib/types';
|
|
||||||
import clamp from 'just-clamp';
|
import clamp from 'just-clamp';
|
||||||
import { persisted } from 'svelte-local-storage-store';
|
import { persisted } from 'svelte-local-storage-store';
|
||||||
|
import type { UserPreferences } from '../types';
|
||||||
|
|
||||||
const _default_user_preferences = { playback_rate: 1, volume: 1 } satisfies UserPreferences;
|
const _default_user_preferences = { playback_rate: 1, volume: 1 } satisfies UserPreferences;
|
||||||
const _user_preferences = persisted<UserPreferences>('USER_PREFERENCE', _default_user_preferences);
|
const _user_preferences = persisted<UserPreferences>('USER_PREFERENCE', _default_user_preferences);
|
||||||
|
|||||||
@@ -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 { persisted } from 'svelte-local-storage-store';
|
||||||
import { get } from 'svelte/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 _default_user_progress = {} satisfies UserProgress;
|
||||||
const _user_progress = persisted<UserProgress>('USER_PROGRESS', _default_user_progress);
|
const _user_progress = persisted<UserProgress>('USER_PROGRESS', _default_user_progress);
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
|
export * from './get-pathname-from-url';
|
||||||
export * from './seconds-to-timestamp';
|
export * from './seconds-to-timestamp';
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { dev } from '$app/environment';
|
import { dev } from '$app/environment';
|
||||||
|
|
||||||
const useLogger = {
|
const useLogger = {
|
||||||
error: console.error,
|
|
||||||
info: console.info,
|
info: console.info,
|
||||||
|
error: console.error,
|
||||||
warn: console.warn,
|
warn: console.warn,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -13,7 +13,11 @@ export function log(type: Logger, ...content: unknown[]) {
|
|||||||
|
|
||||||
if (type === 'info' && !dev) return;
|
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);
|
export const info = (...content: unknown[]) => log('info', ...content);
|
||||||
|
|||||||
@@ -3,14 +3,14 @@ function section(t: number) {
|
|||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function secondsToTimestamp(seconds: number) {
|
export function secondsToTimestamp(seconds: number, force_hours = false) {
|
||||||
const hh = Math.floor(seconds / 3600);
|
const hh = Math.floor(seconds / 3600);
|
||||||
const hh_remainder = seconds % 3600;
|
const hh_remainder = seconds % 3600;
|
||||||
const mm = Math.floor(hh_remainder / 60);
|
const mm = Math.floor(hh_remainder / 60);
|
||||||
const mm_remainder = hh_remainder % 60;
|
const mm_remainder = hh_remainder % 60;
|
||||||
const ss = Math.floor(mm_remainder);
|
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 mins = mm ? `${section(mm)}:` : '00:';
|
||||||
const secs = ss ? `${section(ss)}` : '00';
|
const secs = ss ? `${section(ss)}` : '00';
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { AudioLoader } from '$lib/audio';
|
import { AudioLoader } from 'svelte-podcast';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<AudioLoader />
|
<AudioLoader />
|
||||||
|
|||||||
+60
-12
@@ -1,5 +1,12 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { episode_audio, episode_progress, user_preferences, user_progress } from '$lib';
|
import {
|
||||||
|
episode_audio,
|
||||||
|
episode_progress,
|
||||||
|
PlayerStack,
|
||||||
|
PlayerWidget,
|
||||||
|
user_preferences,
|
||||||
|
user_progress,
|
||||||
|
} from 'svelte-podcast';
|
||||||
|
|
||||||
const sources = {
|
const sources = {
|
||||||
syntax: {
|
syntax: {
|
||||||
@@ -16,6 +23,8 @@
|
|||||||
|
|
||||||
let current_time = 0;
|
let current_time = 0;
|
||||||
$: current_time = $episode_progress.current_time;
|
$: current_time = $episode_progress.current_time;
|
||||||
|
|
||||||
|
$: console.log('details :: ', $episode_audio?.details);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<pre>{JSON.stringify(
|
<pre>{JSON.stringify(
|
||||||
@@ -25,7 +34,7 @@
|
|||||||
$user_preferences,
|
$user_preferences,
|
||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
3,
|
2,
|
||||||
)}</pre>
|
)}</pre>
|
||||||
|
|
||||||
<h1>Demo</h1>
|
<h1>Demo</h1>
|
||||||
@@ -34,7 +43,7 @@
|
|||||||
<button type="button" on:click={user_preferences.clear}>Clear all preferences</button>
|
<button type="button" on:click={user_preferences.clear}>Clear all preferences</button>
|
||||||
|
|
||||||
<h5>Load Audio</h5>
|
<h5>Load Audio</h5>
|
||||||
<button type="button" on:click={() => episode_audio.load(sources['syntax'].src, sources['knomii'])}
|
<button type="button" on:click={() => episode_audio.load(sources['syntax'].src, sources['syntax'])}
|
||||||
>Syntax</button
|
>Syntax</button
|
||||||
>
|
>
|
||||||
<button type="button" on:click={() => episode_audio.load(sources['knomii'].src, sources['knomii'])}
|
<button type="button" on:click={() => episode_audio.load(sources['knomii'].src, sources['knomii'])}
|
||||||
@@ -58,15 +67,6 @@
|
|||||||
|
|
||||||
<h6>Seeking</h6>
|
<h6>Seeking</h6>
|
||||||
|
|
||||||
<input
|
|
||||||
type="range"
|
|
||||||
min={0}
|
|
||||||
max={$episode_audio?.duration}
|
|
||||||
style="width:100%"
|
|
||||||
bind:value={current_time}
|
|
||||||
on:change={(e) => episode_audio.seek(parseInt(e.currentTarget.value))}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<button type="button" on:click={() => episode_audio.seek(30)}>Go to 30s from start </button>
|
<button type="button" on:click={() => episode_audio.seek(30)}>Go to 30s from start </button>
|
||||||
<button type="button" on:click={() => episode_audio.seek(30, 'from-end')}>Go to 30s from end</button
|
<button type="button" on:click={() => episode_audio.seek(30, 'from-end')}>Go to 30s from end</button
|
||||||
>
|
>
|
||||||
@@ -80,3 +80,51 @@
|
|||||||
{rate}x
|
{rate}x
|
||||||
</button>
|
</button>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<!-- <PodcastPlayer
|
||||||
|
artwork={$episode_audio?.details?.artwork}
|
||||||
|
title={$episode_audio?.details?.title || 'Podcast Name'}
|
||||||
|
/> -->
|
||||||
|
|
||||||
|
<br />
|
||||||
|
<PlayerWidget />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<PlayerWidget include={{ playback_rate: true }} />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<PlayerWidget include={{ skip_back: 10, skip_forward: 30 }} />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<PlayerWidget
|
||||||
|
style="width: 100%;"
|
||||||
|
include={{
|
||||||
|
current_time: true,
|
||||||
|
playback_rate: true,
|
||||||
|
duration: true,
|
||||||
|
skip_back: 10,
|
||||||
|
skip_forward: 30,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<PlayerStack style="width:400px;" />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<PlayerStack include={{ playback_rate: true }} />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<PlayerStack include={{ skip_back: 10, skip_forward: 30, timestamps: true }} />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<PlayerStack
|
||||||
|
include={{
|
||||||
|
playback_rate: true,
|
||||||
|
timestamps: true,
|
||||||
|
skip_back: 10,
|
||||||
|
skip_forward: 30,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|||||||
@@ -1,16 +1,108 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { episode_audio, episode_progress } from '$lib/audio';
|
import {
|
||||||
|
episode_audio,
|
||||||
|
episode_progress,
|
||||||
|
PlayerWidget,
|
||||||
|
user_preferences,
|
||||||
|
user_progress,
|
||||||
|
} from 'svelte-podcast';
|
||||||
|
|
||||||
|
const sources = {
|
||||||
|
syntax: {
|
||||||
|
src: `/example-syntax.mp3`,
|
||||||
|
title: `Supper Club × Rich Harris, Author of Svelte`,
|
||||||
|
artwork: `https://ssl-static.libsyn.com/p/assets/b/3/c/d/b3cdf28da11ad39fe5bbc093207a2619/Syntax_-_499.jpg`,
|
||||||
|
},
|
||||||
|
knomii: {
|
||||||
|
src: `/example-knomii.mp3`,
|
||||||
|
title: `Empowerment starts with letting go of control`,
|
||||||
|
artwork: `https://ssl-static.libsyn.com/p/assets/f/a/8/d/fa8d56d5226884335f2e77a3093c12a1/ep-6.png`,
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
let current_time = 0;
|
||||||
|
$: current_time = $episode_progress.current_time;
|
||||||
|
|
||||||
|
$: console.log('details :: ', $episode_audio?.details);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<h1>Demo</h1>
|
|
||||||
|
|
||||||
<a href="/">Demo</a>
|
|
||||||
|
|
||||||
<pre>{JSON.stringify(
|
<pre>{JSON.stringify(
|
||||||
{
|
{
|
||||||
$episode_audio,
|
$episode_audio,
|
||||||
$episode_progress,
|
$episode_progress,
|
||||||
|
$user_preferences,
|
||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
3,
|
2,
|
||||||
)}</pre>
|
)}</pre>
|
||||||
|
|
||||||
|
<h1>Demo</h1>
|
||||||
|
<a href="/another-page">Another Page</a>
|
||||||
|
<button type="button" on:click={user_progress.clear}>Clear progress for all episodes</button>
|
||||||
|
<button type="button" on:click={user_preferences.clear}>Clear all preferences</button>
|
||||||
|
|
||||||
|
<h5>Load Audio</h5>
|
||||||
|
<button type="button" on:click={() => episode_audio.load(sources['syntax'].src, sources['syntax'])}
|
||||||
|
>Syntax</button
|
||||||
|
>
|
||||||
|
<button type="button" on:click={() => episode_audio.load(sources['knomii'].src, sources['knomii'])}
|
||||||
|
>Knomii</button
|
||||||
|
>
|
||||||
|
<button type="button" on:click={() => episode_audio.unload()}>None</button>
|
||||||
|
|
||||||
|
<h5>Custom audio controls</h5>
|
||||||
|
|
||||||
|
<h6>Play / Pause Actions</h6>
|
||||||
|
|
||||||
|
<button type="button" on:click={() => episode_audio.play()}>Play</button>
|
||||||
|
<button type="button" on:click={() => episode_audio.pause()}>Pause</button>
|
||||||
|
<button type="button" on:click={() => episode_audio.pause('toggle')}>Toggle</button>
|
||||||
|
|
||||||
|
<h6>Audio Actions</h6>
|
||||||
|
|
||||||
|
<button type="button" on:click={() => episode_audio.mute()}>Mute</button>
|
||||||
|
<button type="button" on:click={() => episode_audio.unmute()}>Unmute</button>
|
||||||
|
<button type="button" on:click={() => episode_audio.mute('toggle')}>Toggle</button>
|
||||||
|
|
||||||
|
<h6>Seeking</h6>
|
||||||
|
|
||||||
|
<button type="button" on:click={() => episode_audio.seek(30)}>Go to 30s from start </button>
|
||||||
|
<button type="button" on:click={() => episode_audio.seek(30, 'from-end')}>Go to 30s from end</button
|
||||||
|
>
|
||||||
|
<button type="button" on:click={() => episode_audio.skip(10, 'forward')}>Skip 10s</button>
|
||||||
|
<button type="button" on:click={() => episode_audio.skip(10, 'backward')}>Rewind 10s</button>
|
||||||
|
|
||||||
|
<h6>Playback Rate</h6>
|
||||||
|
|
||||||
|
{#each [0.5, 1, 2, 3] as rate}
|
||||||
|
<button type="button" on:click={() => user_preferences.set.playback_rate(rate)}>
|
||||||
|
{rate}x
|
||||||
|
</button>
|
||||||
|
{/each}
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<!-- <PodcastPlayer
|
||||||
|
artwork={$episode_audio?.details?.artwork}
|
||||||
|
title={$episode_audio?.details?.title || 'Podcast Name'}
|
||||||
|
/> -->
|
||||||
|
|
||||||
|
<br />
|
||||||
|
<PlayerWidget />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<PlayerWidget include={{ playback_rate: true }} />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<PlayerWidget include={{ skip_back: 10, skip_forward: 30 }} />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<PlayerWidget
|
||||||
|
include={{
|
||||||
|
current_time: true,
|
||||||
|
playback_rate: true,
|
||||||
|
duration: true,
|
||||||
|
skip_back: 10,
|
||||||
|
skip_forward: 30,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|||||||
+1
-2
@@ -10,8 +10,7 @@ const config = {
|
|||||||
kit: {
|
kit: {
|
||||||
adapter: adapter(),
|
adapter: adapter(),
|
||||||
alias: {
|
alias: {
|
||||||
$lib: 'src/lib',
|
'svelte-podcast': 'src/lib',
|
||||||
$pkg: 'src/lib/utility/package/',
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user