Initial Docs (#39)

This commit is contained in:
Ollie Taylor
2023-07-09 22:18:06 +01:00
committed by GitHub
parent 9232f4d52e
commit e01855b89b
51 changed files with 3056 additions and 613 deletions
+58
View File
@@ -0,0 +1,58 @@
# Hello World
this is some content from @OllieJT on pr #32
this is on https://github.com/OllieJT/svelte-podcast/pull/39
> this is a quote
## this is a subheading
`const this_is = "code"`
```js
const this_is = 'code_block';
console.log(this_is);
```
```js {1,3-4} showLineNumbers
function fancyAlert(arg) {
if (arg) {
$.facebox({ div: '#foo' });
}
}
```
```svelte {1,3-4} showLineNumbers
<script>
import { episode_audio } from 'svelte-podcast';
</script>
<!-- load the episode on click -->
<button
on:click={() =>
episode_audio.load('/episode-audio.mp3', {
/* optional metadata */
})}
>
Load Episode
</button>
<!-- unload the episode on click -->
<button on:click={() => episode_audio.unload()}>Unload Episode</button>
```
[This is a link](https://www.google.com)
- this is a list
- this is a list
- this is a list
1. this is a numbered list
2. this is a numbered list
3. this is a numbered list
| this | is | a | table |
| ---- | --- | --- | ----- |
| this | is | a | table |
| this | is | a | table |
+16
View File
@@ -0,0 +1,16 @@
<script lang="ts">
import { topics } from '$content/utility/anchor-registry';
import { Hashtag } from '@inqling/svelte-icons/heroicon-24-outline';
export let value: string;
$: id = topics.slugify(value || '');
topics.add(value);
</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"
>{value}</span
>
<span class="pointer-events-none absolute -top-10 h-px w-px" {id} />
</a>
@@ -0,0 +1,19 @@
<script lang="ts">
import Anchor from './anchor.svelte';
export let title: string;
export let anchor: boolean = false;
</script>
<li class="list-item list-disc text-primary-800">
<h4 class="text-lg font-medium leading-normal text-primary-600">
{#if anchor}
<Anchor value={title} />
{:else}
{title}
{/if}
</h4>
<p class="mt-0 text-mono-600">
<slot />
</p>
</li>
@@ -0,0 +1,11 @@
<script lang="ts">
import Anchor from './anchor.svelte';
export let title: string;
export let subtitle: string | undefined = undefined;
</script>
<h3 class="text-xl font-medium leading-relaxed text-mono-900"><Anchor value={title} /></h3>
{#if subtitle}
<p class="text-xl font-normal leading-normal text-mono-500">{subtitle}</p>
{/if}
+8
View File
@@ -0,0 +1,8 @@
<script lang="ts">
</script>
<article
class="section-content my-4 w-full border-t-2 border-mono-100 py-4 text-mono-600 first-of-type:border-t-0 first-of-type:pt-0"
>
<slot />
</article>
+29
View File
@@ -0,0 +1,29 @@
<script lang="ts">
import type { SvelteIcon } from '@inqling/svelte-icons';
type Feature = {
icon: SvelteIcon;
title: string;
description: string;
};
export let features: Feature[];
</script>
<dl
class="mx-auto grid max-w-2xl grid-cols-1 gap-6 py-6 text-base leading-7 text-mono-600 sm:grid-cols-2 sm:gap-y-10 lg:mx-0 lg:max-w-none"
>
{#each features as feature}
<div class="relative pl-9">
<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"
/>
{feature.title}
</dt>
<dd class="inline">{feature.description}</dd>
</div>
{/each}
</dl>
+6
View File
@@ -0,0 +1,6 @@
export { default as ContentListItem } from './content-list-item.svelte';
export { default as ContentTitle } from './content-title.svelte';
export { default as Content } from './content.svelte';
export { default as Features } from './features.svelte';
export { default as SectionTitle } from './section-title.svelte';
export { default as Section } from './section.svelte';
@@ -0,0 +1,9 @@
<script lang="ts">
import Anchor from './anchor.svelte';
export let title: string;
</script>
<h2 class="text-3xl font-normal leading-loose text-primary-600">
<Anchor value={title} />
</h2>
+9
View File
@@ -0,0 +1,9 @@
<script lang="ts">
</script>
<!-- <div class="relative mx-auto w-full max-w-7xl p-4 sm:px-6 lg:px-8"> -->
<div class="relative mx-auto w-full max-w-prose p-4 text-lg sm:px-6 lg:px-8">
<section class="w-full">
<slot />
</section>
</div>
+184
View File
@@ -0,0 +1,184 @@
## Table of contents
## What is svelte-podcast?
### Motivation
At it's core svelte-podcast provides tooling to make the following tasks easier:
#### I want to build a custom audio player
The default audio element is quite nice, but there are 2 main reasons why people want to build their own;
1. to customize the look and feel
2. to add custom functionality.
svelte-podcast provides a simple API enabling you to resolve both of these desires.
#### I find managing the state of audio difficult
It's one thing to load, play, and pause audio on a single page, but what if you want to build more custom or advanced behaviours like
> Can audio continue playing when the user navigates to a new page.
> Can I play/pause an episode from content like an article?
> Can I highlight show notes relevant to the current timestamp?
svelte-podcast makes solving these challenges easier by simplifying your interactions with the audio element.
#### I find RSS frustrating to work with
We're still working on this, it'll be coming soon™️!
### Features
| Feature | Description |
| ------------------- | ---------------------------------------------------------------------------------------------- |
| **Simple API** | Get essential audio data like the current timestamp, duration, play state and more... |
| **Simple Controls** | Control your active audio source with play, pause, seek, and more methods... |
| **Extensible** | Define your own metadata for each episode to easily association content with the current audio |
| **Save Progress** | Save and load a users progress and preferences to localStorage, or your own database |
| **Persistence** | If your site makes use of client side routing, audio will continue playing when users navigate |
| **Typescript** | 1st class types, with type overrides for defining your own metadata requirements |
## Get Started
### Install
Install the latest version of svelte-podcast with your preferred package manager.
```sh
# with npm
npm install svelte-podcast@latest
# with yarn
yarn add svelte-podcast@latest
# with pnpm
pnpm add svelte-podcast@latest
```
### Setup
Add the AudioLoader component to your root layout. You must have one of these for svelte-podcast to work. You should also only load one instance of this at a time, and so we recommend you loading it at the base of your app.
```svelte
<!-- /routes/+layout.svelte -->
<script>
import { AudioLoader } from 'svelte-podcast';
</script>
<AudioLoader />
<!-- your layout -->
<slot />
```
### Load an episode
All you need to load an episode is a URL to an audio file. svelte-podcast uses a html audio element under the hood, so any audio file compatible with the autio element is also compatible with this package.
#### Using a URL (Most Common)
An **audio url** could be a URL to an MP3 file from an RSS feed, like this: `https://media.transistor.fm/27a058c9/27b595e2.mp3`. It could also be a path to a static file on your server.
#### Using a static file
If you're using SvelteKit, you can store **static files** in the /static directory. When your site is built, everything in the static directory will be at the root of your site. If you have a file in `/static/episides/episode-01.mp3` you could load it as `/episides/episode-01.mp3`
#### Using the AudioLoader component
Only one piece of audio can be loaded at a time, however a users progress for each audio is saved in localStorage when they play, pause, or skip. You can load audio via the `episode_audio` store from anywhere in your project.
##### Example: Load audio after page is loaded
```svelte
<script>
import { onMount } from 'svelte';
import { episode_audio } from 'svelte-podcast';
onMount(() => {
// load the episode on mount without any metadata
episode_audio.load('/episode-audio.mp3', {
/* optional metadata */
});
});
</script>
```
##### Example: Load audio after a user clicks a button
```svelte
<script>
import { episode_audio } from 'svelte-podcast';
</script>
<!-- load the episode on click -->
<button
on:click={() =>
episode_audio.load('/episode-audio.mp3', {
/* optional metadata */
})}
>
Load Episode
</button>
<!-- unload the episode on click -->
<button on:click={() => episode_audio.unload()}>Unload Episode</button>
```
## Components
### `<PlayerWidget/>`
Coming soon...
### `<PlayerStack/>`
Coming soon...
### `<HeadlessTimeline/>`
Coming soon...
## Utilities
### Debug Mode
Coming soon...
### audio
Coming soon...
### episode_progress
Coming soon...
### episode_details
Coming soon...
### user_progress & user_preferences
Coming soon...
### save_podcast_state
Coming soon...
### secondsToTimestamp
Coming soon...
## Typescript
### Override types
Coming soon...
### Exported types
Coming soon...
+14
View File
@@ -0,0 +1,14 @@
import { assets } from '$app/paths';
export const episodes = {
syntax: {
src: `${assets}/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: `${assets}/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;
+9
View File
@@ -0,0 +1,9 @@
<script>
import { AudioLoader } from 'svelte-podcast';
</script>
<AudioLoader />
<!-- your layout -->
<slot />
+5
View File
@@ -0,0 +1,5 @@
import example_add_loader from './add-loader.svelte?raw';
import example_load_audio_click from './load-audio-click.svelte?raw';
import example_load_audio_mount from './load-audio-mount.svelte?raw';
export { example_add_loader, example_load_audio_click, example_load_audio_mount };
@@ -0,0 +1,16 @@
<script>
import { episode_audio } from 'svelte-podcast';
</script>
<!-- load the episode on click -->
<button
on:click={() =>
episode_audio.load('/episode-audio.mp3', {
/* optional metadata */
})}
>
Load Episode
</button>
<!-- unload the episode on click -->
<button on:click={() => episode_audio.unload()}>Unload Episode</button>
@@ -0,0 +1,11 @@
<script>
import { onMount } from 'svelte';
import { episode_audio } from 'svelte-podcast';
onMount(() => {
// load the episode on mount without any metadata
episode_audio.load('/episode-audio.mp3', {
/* optional metadata */
});
});
</script>
+36
View File
@@ -0,0 +1,36 @@
import { writable } from 'svelte/store';
type Topic = string;
const content = new Set<Topic>();
const ropic_registry = writable<Topic[]>([...content]);
function add(value: Topic) {
ropic_registry.update((prev) => {
const content = new Set<Topic>(prev.filter(Boolean));
Boolean(value) && content.add(value);
return [...content];
});
}
function slugify(value: string) {
// replace all apaces with dashes
const slug = value
.replace(/\s+/g, '-')
.toLowerCase()
.trim()
.replace(/[^\x00-\x7F]/g, '-')
.replace(/[^a-z0-9-]/g, '-')
.replace(/^-+/, '')
.replace(/-+$/, '')
.replace(/--+/g, '-');
return encodeURI(slug);
}
export const topics = {
subscribe: ropic_registry.subscribe,
add,
slugify,
};
+8
View File
@@ -0,0 +1,8 @@
import type { CodeBlockProps } from 'svhighlight/code/CodeBlock.svelte';
export const code_opts = {
background: 'bg-mono-900',
focusType: 'highlight',
highlightColor: 'bg-mono-800',
headerClasses: 'bg-mono-800',
} satisfies CodeBlockProps;