Env Chores (#40)
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte-podcast': minor
|
||||
---
|
||||
|
||||
Updates dependencies
|
||||
@@ -7,6 +7,6 @@ Improves developer logs
|
||||
Fixes various package export issues
|
||||
Adds player components:
|
||||
|
||||
- Player: `<PlayerStack />`
|
||||
- Player: `<PlayerWidget />`
|
||||
- Utility: `<HeadlessTimeline />`
|
||||
- Player: `<PlayerStack />`
|
||||
- Player: `<PlayerWidget />`
|
||||
- Utility: `<HeadlessTimeline />`
|
||||
|
||||
+5
-1
@@ -13,4 +13,8 @@ pnpm-lock.yaml
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
|
||||
**/components/_*
|
||||
**/components/_*
|
||||
|
||||
*.config.ts
|
||||
*.config.js
|
||||
*.config.cjs
|
||||
+18
-3
@@ -1,8 +1,13 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
parser: '@typescript-eslint/parser',
|
||||
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'],
|
||||
plugins: ['svelte3', '@typescript-eslint'],
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
// 'plugin:@typescript-eslint/recommended-requiring-type-checking',
|
||||
'prettier',
|
||||
],
|
||||
plugins: ['svelte3', '@typescript-eslint', 'unused-imports'],
|
||||
ignorePatterns: ['*.cjs'],
|
||||
overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }],
|
||||
settings: {
|
||||
@@ -11,6 +16,7 @@ module.exports = {
|
||||
parserOptions: {
|
||||
sourceType: 'module',
|
||||
ecmaVersion: 2020,
|
||||
project: ['./tsconfig.json'],
|
||||
},
|
||||
env: {
|
||||
browser: true,
|
||||
@@ -18,6 +24,15 @@ module.exports = {
|
||||
node: true,
|
||||
},
|
||||
rules: {
|
||||
'no-restricted-imports': ['error', { patterns: ['$lib', '$lib/*'] }],
|
||||
// '@typescript-eslint/no-inferrable-types': 'off',
|
||||
// '@typescript-eslint/no-unsafe-argument': 'off',
|
||||
// '@typescript-eslint/no-unsafe-assignment': 'off',
|
||||
'logical-assignment-operators': ['error', 'always'],
|
||||
// "no-unused-vars": "off",
|
||||
'unused-imports/no-unused-imports': 'error',
|
||||
'unused-imports/no-unused-vars': [
|
||||
'warn',
|
||||
{ vars: 'all', varsIgnorePattern: '^_', args: 'after-used', argsIgnorePattern: '^_' },
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
+120
-23
@@ -1,32 +1,129 @@
|
||||
name: 'CI'
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
# we call `pnpm playwright install` instead
|
||||
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: '1'
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
|
||||
# cancel in-progress runs on new commits to same PR (gitub.event.number)
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.number || github.sha }}
|
||||
cancel-in-progress: true
|
||||
group: ${{ github.workflow }}-${{ github.event.number || github.sha }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read # to fetch code (actions/checkout)
|
||||
contents: read # to fetch code (actions/checkout)
|
||||
|
||||
jobs:
|
||||
Lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: pnpm/action-setup@v2.2.4
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '16.x'
|
||||
cache: pnpm
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- run: pnpm run lint
|
||||
- run: pnpm run check
|
||||
setup:
|
||||
name: Setup Enviroment
|
||||
timeout-minutes: 4
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
cache_name: ${{ steps.cache.outputs.name }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set Node to v18.13.0
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: v18.13.0
|
||||
|
||||
- name: Get Node version
|
||||
id: node
|
||||
run: echo "version=$(node -v)" >> $GITHUB_OUTPUT
|
||||
#run: echo "::set-output name=version::$(node --v)"
|
||||
|
||||
- name: Get Cache Name
|
||||
id: cache
|
||||
run: echo "name=${{ runner.os }}-node_modules-${{ hashFiles('**/yarn.lock') }}-${{ steps.node.outputs.version }}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Get node_modules cache
|
||||
uses: actions/cache@v3
|
||||
id: node_modules
|
||||
with:
|
||||
path: |
|
||||
**/node_modules
|
||||
**/.svelte-kit
|
||||
|
||||
key: ${{ steps.cache.outputs.name }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
|
||||
- name: Sync generated typings
|
||||
run: yarn run sync
|
||||
|
||||
linting:
|
||||
name: Linting Checks
|
||||
needs: setup
|
||||
timeout-minutes: 4
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Get node_modules cache
|
||||
uses: actions/cache/restore@v3
|
||||
id: cache
|
||||
with:
|
||||
path: |
|
||||
**/node_modules
|
||||
**/.svelte-kit
|
||||
key: ${{ needs.setup.outputs.cache_name }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
|
||||
- name: Lint prettier
|
||||
run: yarn run lint:prettier
|
||||
|
||||
- name: Lint eslint
|
||||
run: yarn run lint:eslint
|
||||
|
||||
type_check:
|
||||
name: Typescript Checks
|
||||
needs: setup
|
||||
timeout-minutes: 4
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Get node_modules cache
|
||||
uses: actions/cache/restore@v3
|
||||
id: cache
|
||||
with:
|
||||
path: |
|
||||
**/node_modules
|
||||
**/.svelte-kit
|
||||
key: ${{ needs.setup.outputs.cache_name }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
|
||||
- name: Check for type errors
|
||||
run: yarn run ts
|
||||
# svelte_check:
|
||||
# name: Svelte Checks
|
||||
# needs: setup
|
||||
# timeout-minutes: 4
|
||||
# runs-on: ubuntu-latest
|
||||
# steps:
|
||||
# - name: Checkout code
|
||||
# uses: actions/checkout@v3
|
||||
#
|
||||
# - name: Get node_modules cache
|
||||
# uses: actions/cache/restore@v3
|
||||
# id: cache
|
||||
# with:
|
||||
# path: |
|
||||
# **/node_modules
|
||||
# **/.svelte-kit
|
||||
# key: ${{ needs.setup.outputs.cache_name }}
|
||||
#
|
||||
# - name: Install dependencies
|
||||
# run: yarn install --frozen-lockfile
|
||||
#
|
||||
# - name: Check for best practices
|
||||
# run: yarn run check
|
||||
|
||||
@@ -1,42 +1,87 @@
|
||||
name: 'Publish to NPM'
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
|
||||
concurrency: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
||||
jobs:
|
||||
release:
|
||||
# prevents this action from running on forks
|
||||
if: github.repository == 'OllieJT/svelte-podcast'
|
||||
permissions:
|
||||
contents: write # to create release (changesets/action)
|
||||
pull-requests: write # to create pull request (changesets/action)
|
||||
name: Release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
# This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits
|
||||
fetch-depth: 0
|
||||
- uses: pnpm/action-setup@v2.2.4
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16.x
|
||||
cache: pnpm
|
||||
setup:
|
||||
name: Setup Enviroment
|
||||
timeout-minutes: 4
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
cache_name: ${{ steps.cache.outputs.name }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- name: Set Node to v18.13.0
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: v18.13.0
|
||||
|
||||
- name: Create Release Pull Request or Publish to npm
|
||||
id: changesets
|
||||
uses: changesets/action@v1
|
||||
with:
|
||||
# This expects you to have a script called release which does a build for your packages and calls changeset publish
|
||||
publish: pnpm release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.TOKEN }}
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
UPDATE_TEMPLATE_SSH_KEY: ${{ secrets.UPDATE_TEMPLATE_SSH_KEY }}
|
||||
- name: Get Node version
|
||||
id: node
|
||||
run: echo "version=$(node -v)" >> $GITHUB_OUTPUT
|
||||
#run: echo "::set-output name=version::$(node --v)"
|
||||
|
||||
- name: Get Cache Name
|
||||
id: cache
|
||||
run: echo "name=${{ runner.os }}-node_modules-${{ hashFiles('**/yarn.lock') }}-${{ steps.node.outputs.version }}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Get node_modules cache
|
||||
uses: actions/cache@v3
|
||||
id: node_modules
|
||||
with:
|
||||
path: |
|
||||
**/node_modules
|
||||
**/.svelte-kit
|
||||
|
||||
key: ${{ steps.cache.outputs.name }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
|
||||
- name: Sync generated typings
|
||||
run: yarn run sync
|
||||
release:
|
||||
if: github.repository == 'OllieJT/svelte-podcast'
|
||||
name: Release
|
||||
needs: setup
|
||||
timeout-minutes: 5
|
||||
runs-on: ubuntu-latest
|
||||
# prevents this action from running on forks
|
||||
permissions:
|
||||
contents: write # to create release (changesets/action)
|
||||
pull-requests: write # to create pull request (changesets/action)
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
# This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Get node_modules cache
|
||||
uses: actions/cache/restore@v3
|
||||
id: cache
|
||||
with:
|
||||
path: |
|
||||
**/node_modules
|
||||
**/.svelte-kit
|
||||
key: ${{ needs.setup.outputs.cache_name }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
|
||||
- name: Create Release Pull Request or Publish to npm
|
||||
id: changesets
|
||||
uses: changesets/action@v1
|
||||
with:
|
||||
# This expects you to have a script called release which does a build for your packages and calls changeset publish
|
||||
publish: yarn release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.TOKEN }}
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
UPDATE_TEMPLATE_SSH_KEY: ${{ secrets.UPDATE_TEMPLATE_SSH_KEY }}
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
name: 'CI'
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- todo
|
||||
|
||||
env:
|
||||
# we call `pnpm playwright install` instead
|
||||
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: '1'
|
||||
|
||||
# cancel in-progress runs on new commits to same PR (gitub.event.number)
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.number || github.sha }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read # to fetch code (actions/checkout)
|
||||
|
||||
jobs:
|
||||
Lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: pnpm/action-setup@v2.2.4
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '16.x'
|
||||
cache: pnpm
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- run: pnpm run lint
|
||||
- run: pnpm run check
|
||||
Tests:
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 30
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- node-version: 16
|
||||
os: ubuntu-latest
|
||||
e2e-browser: 'chromium'
|
||||
- node-version: 18
|
||||
os: ubuntu-latest
|
||||
e2e-browser: 'chromium'
|
||||
env:
|
||||
KIT_E2E_BROWSER: ${{matrix.e2e-browser}}
|
||||
steps:
|
||||
- run: git config --global core.autocrlf false
|
||||
- uses: actions/checkout@v3
|
||||
- uses: pnpm/action-setup@v2.2.4
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: pnpm
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- run: pnpm playwright install ${{ matrix.e2e-browser }}
|
||||
- run: pnpm test
|
||||
- name: Archive test results
|
||||
if: failure()
|
||||
shell: bash
|
||||
run: find packages -type d -name test-results -not -empty | tar -czf test-results.tar.gz --files-from=-
|
||||
- name: Upload test results
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
retention-days: 3
|
||||
name: test-failure-${{ github.run_id }}-${{ matrix.os }}-${{ matrix.node-version }}-${{ matrix.e2e-browser }}
|
||||
path: test-results.tar.gz
|
||||
Cross-browser-test:
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 30
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- node-version: 16
|
||||
os: windows-2019 # slowness reported on newer versions https://github.com/actions/runner-images/issues/5166
|
||||
e2e-browser: 'chromium'
|
||||
mode: 'dev'
|
||||
- node-version: 16
|
||||
os: ubuntu-latest
|
||||
e2e-browser: 'firefox'
|
||||
mode: 'dev'
|
||||
- node-version: 16
|
||||
os: macOS-latest
|
||||
e2e-browser: 'webkit'
|
||||
mode: 'dev'
|
||||
- node-version: 16
|
||||
os: windows-2019 # slowness reported on newer versions https://github.com/actions/runner-images/issues/5166
|
||||
e2e-browser: 'chromium'
|
||||
mode: 'build'
|
||||
- node-version: 16
|
||||
os: ubuntu-latest
|
||||
e2e-browser: 'firefox'
|
||||
mode: 'build'
|
||||
- node-version: 16
|
||||
os: macOS-latest
|
||||
e2e-browser: 'webkit'
|
||||
mode: 'build'
|
||||
env:
|
||||
KIT_E2E_BROWSER: ${{matrix.e2e-browser}}
|
||||
steps:
|
||||
- run: git config --global core.autocrlf false
|
||||
- uses: actions/checkout@v3
|
||||
- uses: pnpm/action-setup@v2.2.4
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: pnpm
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- run: pnpm playwright install ${{ matrix.e2e-browser }}
|
||||
- run: pnpm test:cross-platform:${{ matrix.mode }}
|
||||
- name: Archive test results
|
||||
if: failure()
|
||||
shell: bash
|
||||
run: find packages -type d -name test-results -not -empty | tar -czf test-results-cross-platform-${{ matrix.mode }}.tar.gz --files-from=-
|
||||
- name: Upload test results
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
retention-days: 3
|
||||
name: test-failure-cross-platform-${{ matrix.mode }}-${{ github.run_id }}-${{ matrix.os }}-${{ matrix.node-version }}-${{ matrix.e2e-browser }}
|
||||
path: test-results-cross-platform-${{ matrix.mode }}.tar.gz
|
||||
+14
-8
@@ -1,12 +1,18 @@
|
||||
{
|
||||
"useTabs": true,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all",
|
||||
"printWidth": 100,
|
||||
"plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"],
|
||||
"svelteSortOrder": "options-scripts-styles-markup",
|
||||
"svelteBracketNewLine": true,
|
||||
"svelteIndentScriptAndStyle": true,
|
||||
"pluginSearchDirs": ["."],
|
||||
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
|
||||
"arrowParens": "always",
|
||||
"bracketSpacing": true,
|
||||
"bracketSameLine": false,
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"useTabs": true,
|
||||
"tabWidth": 3,
|
||||
"trailingComma": "all",
|
||||
"overrides": [
|
||||
{
|
||||
"files": "*.svelte",
|
||||
"options": { "parser": "svelte" }
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Vendored
+22
-13
@@ -1,18 +1,31 @@
|
||||
{
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.formatOnType": false,
|
||||
"editor.formatOnSave": true,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": true,
|
||||
"source.organizeImports": true
|
||||
"[svelte]": {
|
||||
"editor.defaultFormatter": "svelte.svelte-vscode",
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.organizeImports": true
|
||||
}
|
||||
},
|
||||
"eslint.packageManager": "pnpm",
|
||||
"eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact", "svelte"],
|
||||
"[typescript]": {
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.organizeImports": true
|
||||
}
|
||||
},
|
||||
"eslint.rules.customizations": [{ "rule": "*", "severity": "warn" }],
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.formatOnSave": true,
|
||||
"editor.formatOnType": false,
|
||||
"files.exclude": {
|
||||
"**/.cache": true,
|
||||
"**/.DS_Store": true,
|
||||
"**/.gitattributes": true,
|
||||
"**/.svelte-kit": true,
|
||||
"**/*-lock.*": true,
|
||||
"**/*.Identifier": true,
|
||||
"**/*.map": true,
|
||||
"**/.turbo": true,
|
||||
"**/.vercel": true,
|
||||
"**/dist": true,
|
||||
"**/node_modules": true,
|
||||
"**/tsconfig.tsbuildinfo": true,
|
||||
"**/.npmrc": true
|
||||
@@ -21,9 +34,5 @@
|
||||
"**/node_modules": true,
|
||||
"**/.svelte-kit": true
|
||||
},
|
||||
"problems.sortOrder": "severity",
|
||||
"todo-tree.tree.scanMode": "workspace only",
|
||||
"javascript.preferences.importModuleSpecifier": "relative",
|
||||
"typescript.preferences.importModuleSpecifier": "relative",
|
||||
"files.associations": { ".env*": "dotenv", "*.svx": "mdx", "*.md": "mdx" }
|
||||
"problems.sortOrder": "severity"
|
||||
}
|
||||
|
||||
+18
-18
@@ -4,67 +4,67 @@
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- feba0d4: Improvements to audio stores:
|
||||
- feba0d4: Improvements to audio stores:
|
||||
|
||||
- Adds missing `is_paused` value.
|
||||
- Fixes to `start_at` value
|
||||
- Refactors localStorage stores & user preferences
|
||||
- Adds missing `is_paused` value.
|
||||
- Fixes to `start_at` value
|
||||
- Refactors localStorage stores & user preferences
|
||||
|
||||
## 0.4.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- ff6a6d9: refactored audio element bindings for better control over element
|
||||
- ff6a6d9: refactored audio element bindings for better control over element
|
||||
|
||||
## 0.3.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- ff5caf2: fix to allow override of internal types
|
||||
- ff5caf2: fix to allow override of internal types
|
||||
|
||||
## 0.3.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 802c704: fixes dist exports
|
||||
- 802c704: fixes dist exports
|
||||
|
||||
## 0.3.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 6c849b7: Fixes derived store causing exessive updates
|
||||
- 6c849b7: Fixes derived store causing exessive updates
|
||||
|
||||
## 0.3.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 02598d4: fixes exported typings
|
||||
- 02598d4: fixes exported typings
|
||||
|
||||
## 0.3.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 0b12aab: Adds mechanic for managing user preferences
|
||||
- 0b12aab: Adds mechanic for managing user preferences
|
||||
|
||||
## 0.2.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 6f89448: Adds the ability to bind episode metadata to the audio store
|
||||
- a70d68d:
|
||||
- Restructures lib to make dist cleaner and dev easier to grock
|
||||
- Refactors <audio /> bindings to make it easier to change values when loading a different source
|
||||
- Moves more values to micro-stores
|
||||
- 1841199: Adds save/load mechanic for episode progress
|
||||
- 6f89448: Adds the ability to bind episode metadata to the audio store
|
||||
- a70d68d:
|
||||
- Restructures lib to make dist cleaner and dev easier to grock
|
||||
- Refactors <audio /> bindings to make it easier to change values when loading a different source
|
||||
- Moves more values to micro-stores
|
||||
- 1841199: Adds save/load mechanic for episode progress
|
||||
|
||||
## 0.1.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 549d858: Fixes release build
|
||||
- 549d858: Fixes release build
|
||||
|
||||
## 0.1.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 2e6f082: Adds initial audio element abstraction with store
|
||||
- 2e6f082: Adds initial audio element abstraction with store
|
||||
|
||||
@@ -8,27 +8,27 @@ A collection of tools for building podcast websites and tools with Svelte or Sve
|
||||
|
||||
## What's inside?
|
||||
|
||||
- 🔊 Load and play audio files via URL or local files
|
||||
- 🔃 Navigate via client-side routing while audio continues to play
|
||||
- 🎛️ Simpler control over audio playback:
|
||||
- Seek to a specific time
|
||||
- skip forward ﹢ backward
|
||||
- play ﹢ pause
|
||||
- mute ﹢ unmute
|
||||
- 🛟 Save and load a users progress for each episode in localStorage
|
||||
- 💾 Save and load a users preferences (like playback speed) in localStorage
|
||||
- ﹢ volume
|
||||
- ﹢ playback speed
|
||||
- 🖼️ Inject episode metadata into the audio store for ea
|
||||
- 🔊 Load and play audio files via URL or local files
|
||||
- 🔃 Navigate via client-side routing while audio continues to play
|
||||
- 🎛️ Simpler control over audio playback:
|
||||
- Seek to a specific time
|
||||
- skip forward ﹢ backward
|
||||
- play ﹢ pause
|
||||
- mute ﹢ unmute
|
||||
- 🛟 Save and load a users progress for each episode in localStorage
|
||||
- 💾 Save and load a users preferences (like playback speed) in localStorage
|
||||
- ﹢ volume
|
||||
- ﹢ playback speed
|
||||
- 🖼️ Inject episode metadata into the audio store for ea
|
||||
|
||||
**Roadmap**
|
||||
In no particular order, here are some of the things I'm confident will be added to this library:
|
||||
|
||||
- ☐ Podcast player component utilities
|
||||
- ☐ Pre-built player component
|
||||
- ☐ RSS Feed parsing
|
||||
- ☐ Looping segments of an episode
|
||||
- [And more ideas being discussed](https://github.com/OllieJT/svelte-podcast/labels/feature)
|
||||
- ☐ Podcast player component utilities
|
||||
- ☐ Pre-built player component
|
||||
- ☐ RSS Feed parsing
|
||||
- ☐ Looping segments of an episode
|
||||
- [And more ideas being discussed](https://github.com/OllieJT/svelte-podcast/labels/feature)
|
||||
|
||||
## Docs
|
||||
|
||||
|
||||
+33
-37
@@ -13,17 +13,17 @@
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "vite dev",
|
||||
"build": "vite build && pnpm package",
|
||||
"build": "vite build && yarn package",
|
||||
"preview": "vite preview",
|
||||
"package": "svelte-kit sync && svelte-package && publint",
|
||||
"test": "playwright test",
|
||||
"sync": "svelte-kit sync",
|
||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
||||
"lint:prettier": "prettier --check --plugin-search-dir=. .",
|
||||
"lint:eslint": "TIMING=1 eslint . --ext .ts,.tsx,.svelte --cache",
|
||||
"lint": "pnpm lint:prettier && pnpm lint:eslint",
|
||||
"lint": "yarn lint:prettier && yarn lint:eslint",
|
||||
"format": "prettier --write --plugin-search-dir=. .",
|
||||
"release": "pnpm package && changeset publish",
|
||||
"release": "yarn package && changeset publish",
|
||||
"ts": "tsc --pretty --noImplicitAny --noEmit"
|
||||
},
|
||||
"exports": {
|
||||
@@ -36,63 +36,59 @@
|
||||
"dist"
|
||||
],
|
||||
"peerDependencies": {
|
||||
"svelte": "^3.55.1"
|
||||
"svelte": ">=3.00.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@inqling/svelte-icons": "^3.1.0",
|
||||
"@inqling/svelte-icons": "^3.3.2",
|
||||
"clsx": "^1.2.1",
|
||||
"just-clamp": "^4.2.0",
|
||||
"svelte-local-storage-store": "^0.4.0"
|
||||
"svelte-local-storage-store": "^0.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@changesets/cli": "^2.26.0",
|
||||
"@playwright/test": "^1.31.2",
|
||||
"@sveltejs/adapter-static": "^2.0.1",
|
||||
"@sveltejs/kit": "^1.11.0",
|
||||
"@sveltejs/package": "^2.0.2",
|
||||
"@changesets/cli": "^2.26.2",
|
||||
"@sveltejs/adapter-static": "^2.0.2",
|
||||
"@sveltejs/kit": "^1.22.1",
|
||||
"@sveltejs/package": "^2.1.0",
|
||||
"@tailwindcss/forms": "^0.5.3",
|
||||
"@tailwindcss/line-clamp": "^0.4.2",
|
||||
"@tailwindcss/line-clamp": "^0.4.4",
|
||||
"@tailwindcss/typography": "^0.5.9",
|
||||
"@typescript-eslint/eslint-plugin": "^5.54.1",
|
||||
"@typescript-eslint/parser": "^5.54.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5.61.0",
|
||||
"@typescript-eslint/parser": "^5.61.0",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"eslint": "^8.36.0",
|
||||
"eslint-config-prettier": "^8.7.0",
|
||||
"eslint": "^8.44.0",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"eslint-plugin-svelte3": "^4.0.0",
|
||||
"highlight.js": "^11.7.0",
|
||||
"postcss": "^8.4.21",
|
||||
"eslint-plugin-unused-imports": "^2.0.0",
|
||||
"highlight.js": "^11.8.0",
|
||||
"postcss": "^8.4.25",
|
||||
"postcss-load-config": "^4.0.1",
|
||||
"prettier": "^2.8.4",
|
||||
"prettier-plugin-svelte": "^2.9.0",
|
||||
"prettier-plugin-tailwindcss": "^0.2.4",
|
||||
"publint": "^0.1.10",
|
||||
"prettier": "^2.8.8",
|
||||
"prettier-plugin-svelte": "^2.10.1",
|
||||
"prettier-plugin-tailwindcss": "^0.3.0",
|
||||
"publint": "^0.1.16",
|
||||
"rehype-add-classes": "^1.0.0",
|
||||
"rehype-autolink-headings": "^6.1.1",
|
||||
"rehype-external-links": "^2.0.1",
|
||||
"rehype-external-links": "^2.1.0",
|
||||
"rehype-highlight": "^6.0.0",
|
||||
"rehype-sanitize": "^5.0.1",
|
||||
"rehype-slug": "^5.1.0",
|
||||
"rehype-stringify": "^9.0.3",
|
||||
"remark-gfm": "^3.0.1",
|
||||
"remark-github": "^11.2.4",
|
||||
"remark-parse": "^10.0.1",
|
||||
"remark-parse": "^10.0.2",
|
||||
"remark-rehype": "^10.1.0",
|
||||
"remark-toc": "^8.0.1",
|
||||
"svelte": "^3.56.0",
|
||||
"svelte-check": "^3.1.2",
|
||||
"svelte-preprocess": "^4.10.7",
|
||||
"svelte": "^4.0.5",
|
||||
"svelte-check": "^3.4.5",
|
||||
"svelte-preprocess": "^5.0.4",
|
||||
"svhighlight": "^0.7.1",
|
||||
"tailwindcss": "^3.2.7",
|
||||
"tslib": "^2.5.0",
|
||||
"typescript": "^4.9.5",
|
||||
"tailwindcss": "^3.3.2",
|
||||
"tslib": "^2.6.0",
|
||||
"typescript": "^5.1.6",
|
||||
"unified": "^10.1.2",
|
||||
"vite": "^4.1.4"
|
||||
"vite": "^4.4.2"
|
||||
},
|
||||
"svelte": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"type": "module",
|
||||
"packageManager": "pnpm@7.28.0",
|
||||
"engines": {
|
||||
"pnpm": "^7.0.0"
|
||||
}
|
||||
"type": "module"
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
import type { PlaywrightTestConfig } from '@playwright/test';
|
||||
|
||||
const config: PlaywrightTestConfig = {
|
||||
webServer: {
|
||||
command: 'npm run build && npm run preview',
|
||||
port: 4173,
|
||||
},
|
||||
testDir: 'tests',
|
||||
};
|
||||
|
||||
export default config;
|
||||
Generated
-4867
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -17,7 +17,7 @@
|
||||
|
||||
@layer components {
|
||||
.prose code {
|
||||
@apply inline rounded bg-primary-100 py-1 px-2 font-mono leading-none text-primary-800;
|
||||
@apply inline rounded bg-primary-100 px-2 py-1 font-mono leading-none text-primary-800;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
.prose code::before,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { topics } from '$content/utility/anchor-registry';
|
||||
import { topics } from '$src/content/utility/anchor-registry';
|
||||
import { Hashtag } from '@inqling/svelte-icons/heroicon-24-outline';
|
||||
|
||||
export let value: string;
|
||||
@@ -8,8 +8,9 @@
|
||||
</script>
|
||||
|
||||
<a href="/#{id}" class="group relative -ml-[1em] hover:text-black">
|
||||
<Hashtag class="h-[1em] w-[1em] -translate-x-1 text-mono-300 group-hover:text-primary-600" /><span
|
||||
class="underline decoration-primary-50/0 decoration-4 group-hover:decoration-primary-500"
|
||||
<Hashtag
|
||||
class="h-[1em] w-[1em] -translate-x-1 text-mono-300 group-hover:text-primary-600"
|
||||
/><span class="underline decoration-primary-50/0 decoration-4 group-hover:decoration-primary-500"
|
||||
>{value}</span
|
||||
>
|
||||
<span class="pointer-events-none absolute -top-10 h-px w-px" {id} />
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<dt class="inline font-semibold text-mono-900">
|
||||
<svelte:component
|
||||
this={feature.icon}
|
||||
class="absolute top-1 left-1 h-5 w-5 text-primary-600"
|
||||
class="absolute left-1 top-1 h-5 w-5 text-primary-600"
|
||||
/>
|
||||
|
||||
{feature.title}
|
||||
|
||||
@@ -20,6 +20,7 @@ function slugify(value: string) {
|
||||
.replace(/\s+/g, '-')
|
||||
.toLowerCase()
|
||||
.trim()
|
||||
// eslint-disable-next-line no-control-regex
|
||||
.replace(/[^\x00-\x7F]/g, '-')
|
||||
.replace(/[^a-z0-9-]/g, '-')
|
||||
.replace(/^-+/, '')
|
||||
|
||||
@@ -26,9 +26,9 @@
|
||||
<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--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);
|
||||
|
||||
@@ -19,6 +19,22 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<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')}
|
||||
/>
|
||||
|
||||
<style>
|
||||
input[type='range'] {
|
||||
--track--shape--height: calc(var(--svpod--timeline-track--shape--height));
|
||||
@@ -127,19 +143,3 @@
|
||||
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')}
|
||||
/>
|
||||
|
||||
@@ -34,6 +34,99 @@
|
||||
const { class: ClassName, ...rest } = $$restProps;
|
||||
</script>
|
||||
|
||||
<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>
|
||||
|
||||
<style>
|
||||
.svpod--container {
|
||||
--fg: var(--svpod--content--base);
|
||||
@@ -227,92 +320,3 @@
|
||||
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>
|
||||
|
||||
@@ -38,6 +38,82 @@
|
||||
const { class: ClassName, ...rest } = $$restProps;
|
||||
</script>
|
||||
|
||||
<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>
|
||||
|
||||
<style>
|
||||
.svpod--container {
|
||||
--fg: var(--svpod--content--base);
|
||||
@@ -157,78 +233,3 @@
|
||||
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>
|
||||
|
||||
@@ -4,62 +4,6 @@
|
||||
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>
|
||||
@@ -153,3 +97,59 @@
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<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>
|
||||
|
||||
@@ -2,6 +2,26 @@
|
||||
export let size = 24;
|
||||
</script>
|
||||
|
||||
<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>
|
||||
|
||||
<style>
|
||||
div.svpod--spinner-container {
|
||||
display: inline-block;
|
||||
@@ -40,23 +60,3 @@
|
||||
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>
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
$: timestamp = secondsToTimestamp(value, force_hours);
|
||||
</script>
|
||||
|
||||
<span style="width:{timestamp.length}ch">{timestamp}</span>
|
||||
|
||||
<style>
|
||||
span {
|
||||
letter-spacing: 0.5px;
|
||||
@@ -15,5 +17,3 @@
|
||||
width: 8ch;
|
||||
}
|
||||
</style>
|
||||
|
||||
<span style="width:{timestamp.length}ch">{timestamp}</span>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
class="sticky top-0 z-50 border-b border-mono-100 bg-white text-lg leading-none lg:overflow-y-visible"
|
||||
id="navigation"
|
||||
>
|
||||
<div class="mx-auto max-w-prose px-4 py-1 sm:py-2 sm:px-6 lg:px-8">
|
||||
<div class="mx-auto max-w-prose px-4 py-1 sm:px-6 sm:py-2 lg:px-8">
|
||||
<div class="relative grid grid-cols-12 gap-1 text-base md:gap-3">
|
||||
<div class="col-span-2 flex items-center justify-start leading-none">
|
||||
<a href="{base}/#navigation" class="flex-shrink-0 py-1">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import content from '$content/docs.md?raw';
|
||||
import content from '$src/content/docs.md?raw';
|
||||
import type { PageServerLoad } from './$types';
|
||||
import { use_markdown } from './use-markdown';
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { base } from '$app/paths';
|
||||
import { Section } from '$content/components';
|
||||
// import Docs from '$content/docs.md';
|
||||
import { episodes } from '$content/episodes';
|
||||
import { Section } from '$src/content/components';
|
||||
// import Docs from '$src/content/docs.md';
|
||||
import { episodes } from '$src/content/episodes';
|
||||
import { onMount } from 'svelte';
|
||||
import { episode_audio, PlayerWidget } from 'svelte-podcast';
|
||||
import type { PageServerData } from './$types';
|
||||
@@ -54,15 +54,16 @@
|
||||
</span>
|
||||
</h1>
|
||||
<p class="mt-6 text-xl leading-8 text-mono-600">
|
||||
A suite of tools and components to build your own podcast players, and work with RSS
|
||||
podcast data in SvelteKit.
|
||||
A suite of tools and components to build your own podcast players, and work with
|
||||
RSS podcast data in SvelteKit.
|
||||
<span class="mt-3 block text-base leading-none text-primary-800">
|
||||
<span
|
||||
class="inline-block rounded-full bg-primary-50 px-3 py-1.5 text-xs font-medium uppercase tracking-wider text-primary-600"
|
||||
>
|
||||
Coming Soon<span class="sr-only">:</span>
|
||||
</span>
|
||||
<span class="tracking-wide">SSR utilities for consuming RSS podcast feeds</span>
|
||||
<span class="tracking-wide">SSR utilities for consuming RSS podcast feeds</span
|
||||
>
|
||||
</span>
|
||||
</p>
|
||||
<div class="mt-10 flex items-center justify-center gap-x-3">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { Section } from '$content/components';
|
||||
import { Section } from '$src/content/components';
|
||||
import {
|
||||
episode_audio,
|
||||
episode_progress,
|
||||
@@ -62,7 +62,11 @@
|
||||
</div>
|
||||
<div>
|
||||
<label for="pw_playback_rate">playback_rate</label>
|
||||
<input id="pw_playback_rate" type="checkbox" bind:checked={player_widget.playback_rate} />
|
||||
<input
|
||||
id="pw_playback_rate"
|
||||
type="checkbox"
|
||||
bind:checked={player_widget.playback_rate}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="pw_duration">duration</label>
|
||||
@@ -87,7 +91,11 @@
|
||||
<svelte:fragment slot="options">
|
||||
<div>
|
||||
<label for="pw_playback_rate">playback_rate</label>
|
||||
<input id="pw_playback_rate" type="checkbox" bind:checked={player_stack.playback_rate} />
|
||||
<input
|
||||
id="pw_playback_rate"
|
||||
type="checkbox"
|
||||
bind:checked={player_stack.playback_rate}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="pw_timestamps">timestamps</label>
|
||||
|
||||
@@ -40,11 +40,14 @@ export function hljsDefineSvelte(hljs: HLJSApi) {
|
||||
subLanguage: 'javascript',
|
||||
contains: [
|
||||
{
|
||||
// eslint-disable-next-line no-useless-escape
|
||||
begin: /[\{]/,
|
||||
// eslint-disable-next-line no-useless-escape
|
||||
end: /[\}]/,
|
||||
skip: true,
|
||||
},
|
||||
{
|
||||
// eslint-disable-next-line no-useless-escape
|
||||
begin: /([#:\/@])(if|else|each|await|then|catch|debug|html)/gm,
|
||||
className: 'keyword',
|
||||
relevance: 10,
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ const config = {
|
||||
adapter: adapter(),
|
||||
alias: {
|
||||
'svelte-podcast': 'src/lib',
|
||||
$content: 'src/content/',
|
||||
$src: 'src',
|
||||
},
|
||||
|
||||
paths: {
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
test('index page has expected h1', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await expect(page.getByRole('heading', { name: 'Welcome to SvelteKit' })).toBeVisible();
|
||||
});
|
||||
Reference in New Issue
Block a user