Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/media-players.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@dskripchenko/ui": minor
---

Media players without dependencies. `UidVideo` — native `<video>` with the kit's controls: scrub bar with buffered ranges, chapters and sprite thumbnails, volume, speed and quality menus, WebVTT subtitles drawn by the player, full screen (iOS fallback), picture-in-picture, resume position, hotkeys, double-tap seek, auto-hiding controls. `UidAudio` — compact row, `mini` variant for tables, waveform decoded in the browser (chunked, cached, size-capped) or from `peaks`, playlist with auto-advance and Media Session. `useMediaController` is the shared core (one active player per page, normalised state, readable localised errors; `media` locale bag in `en`/`ru`). New lazily loaded entry `@dskripchenko/ui/hls`: native HLS where available, otherwise MSE with fMP4/CMAF and MPEG-TS (built-in H.264/AAC → fMP4 transmuxer), AES-128, live playlists, discontinuities, alternate audio renditions in their own SourceBuffer (fMP4, MPEG-TS or packed AAC; audio-track menu in UidVideo), ABR with manual quality selection, retries. UidAudio plays HLS sources too.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ storybook-static
coverage
.npmrc
stats.html
.media-fixtures
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ A Vue 3 component, token, and theme library on CSS custom properties.
- **i18n** — built-in `ru` + `en` locales, `UidLocaleProvider` for partial overrides or custom locales
- **~1500 icons** — `lucide-vue-next` under the hood + `@dskripchenko/ui/icons` sub-export
- **Zero runtime chart deps** — built-in SVG primitives (Sparkline, ProgressRing, Gauge, Heatmap)
- **Media players without dependencies** — video and audio on the native elements, in-browser waveform, HLS (fMP4 and MPEG-TS) in a lazily loaded entry

## Install

Expand Down Expand Up @@ -95,19 +96,21 @@ A short selection — the full catalog is in [Storybook](https://dskripchenko.gi

**Charts:** Sparkline, ProgressRing, Gauge, Heatmap

**Media:** Video, Audio (waveform, mini, playlist), HLS adapter (`@dskripchenko/ui/hls`)

**Wizards:** Stepper, Wizard, WizardStep

**Patterns:** Header, Footer, Sidebar, PageHeader, EmptyState, ErrorState, Result

**Layouts:** SimpleLayout, SidebarLayout, AuthLayout, WizardLayout

**Composables:** useTheme, useLocale, useField, useToast, useWizard, useSidebar, useCommandPalette, useFocusTrap, useScrollLock, usePopover
**Composables:** useMediaController, useTheme, useLocale, useField, useToast, useWizard, useSidebar, useCommandPalette, useFocusTrap, useScrollLock, usePopover

## Documentation

User docs are translated into four languages — pick yours:

- 🇬🇧 **English** (default): [getting-started](./docs/en/getting-started.md), [theming](./docs/en/theming.md), [tokens](./docs/en/tokens.md), [icons](./docs/en/icons.md), [patterns](./docs/en/patterns.md), [validation](./docs/en/validation.md), [charts](./docs/en/charts.md), [markdown](./docs/en/markdown.md), [i18n](./docs/en/i18n.md)
- 🇬🇧 **English** (default): [getting-started](./docs/en/getting-started.md), [theming](./docs/en/theming.md), [tokens](./docs/en/tokens.md), [icons](./docs/en/icons.md), [patterns](./docs/en/patterns.md), [validation](./docs/en/validation.md), [charts](./docs/en/charts.md), [markdown](./docs/en/markdown.md), [video](./docs/en/video.md), [audio](./docs/en/audio.md), [i18n](./docs/en/i18n.md)
- 🇷🇺 **Русский**: [docs/ru/](./docs/ru/)
- 🇩🇪 **Deutsch**: [docs/de/](./docs/de/)
- 🇨🇳 **中文**: [docs/zh/](./docs/zh/)
Expand Down
7 changes: 5 additions & 2 deletions docs/de/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Eine Bibliothek aus Vue-3-Komponenten, Tokens und Themes auf Basis von CSS Custo
- **i18n** — eingebaute `ru` + `en` Locales, `UidLocaleProvider` für partielle Überschreibungen und eigene Locales
- **~1500 Icons** — `lucide-vue-next` unter der Haube + Sub-Export `@dskripchenko/ui/icons`
- **Keine Runtime-Chart-Deps** — eingebaute SVG-Primitive (Sparkline, ProgressRing, Gauge, Heatmap)
- **Mediaplayer ohne Abhängigkeiten** — Video und Audio auf den nativen Elementen, Wellenform im Browser, HLS (fMP4 und MPEG-TS) in einem bei Bedarf geladenen Entry

## Installation

Expand Down Expand Up @@ -85,21 +86,23 @@ Kurze Auswahl — vollständiger Katalog im [Storybook](https://dskripchenko.git

**Charts:** Sparkline, ProgressRing, Gauge, Heatmap

**Medien:** Video, Audio (Wellenform, Mini, Playlist), HLS-Adapter (`@dskripchenko/ui/hls`)

**Wizards:** Stepper, Wizard, WizardStep

**Patterns:** Header, Footer, Sidebar, PageHeader, EmptyState, ErrorState, Result

**Layouts:** SimpleLayout, SidebarLayout, AuthLayout, WizardLayout

**Composables:** useTheme, useLocale, useField, useToast, useWizard, useSidebar, useCommandPalette, useFocusTrap, useScrollLock, usePopover
**Composables:** useMediaController, useTheme, useLocale, useField, useToast, useWizard, useSidebar, useCommandPalette, useFocusTrap, useScrollLock, usePopover

## Dokumentation

Anwender-Dokumentation in vier Sprachen — wähle deine:

- 🇬🇧 **English** (default): [docs/en/](../../docs/en/)
- 🇷🇺 **Русский**: [docs/ru/](../../docs/ru/)
- 🇩🇪 **Deutsch**: [Erste Schritte](../../docs/de/getting-started.md), [Theming](../../docs/de/theming.md), [Tokens](../../docs/de/tokens.md), [Icons](../../docs/de/icons.md), [Patterns](../../docs/de/patterns.md), [Validation](../../docs/de/validation.md), [Charts](../../docs/de/charts.md), [Markdown](../../docs/de/markdown.md), [i18n](../../docs/de/i18n.md)
- 🇩🇪 **Deutsch**: [Erste Schritte](../../docs/de/getting-started.md), [Theming](../../docs/de/theming.md), [Tokens](../../docs/de/tokens.md), [Icons](../../docs/de/icons.md), [Patterns](../../docs/de/patterns.md), [Validation](../../docs/de/validation.md), [Charts](../../docs/de/charts.md), [Markdown](../../docs/de/markdown.md), [Video](../../docs/de/video.md), [Audio](../../docs/de/audio.md), [i18n](../../docs/de/i18n.md)
- 🇨🇳 **中文**: [docs/zh/](../../docs/zh/)

Mitwirkenden-Dokumentation (nur Englisch): [Architecture](../internal/architecture.md), [Component guidelines](../internal/component-guidelines.md), [Contributing](../../.github/CONTRIBUTING.md), [Roadmap](../internal/roadmap.md).
Expand Down
78 changes: 78 additions & 0 deletions docs/de/audio.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Audio

`UidAudio` ist ein Audioplayer auf dem nativen Element `<audio>`: eine kompakte Zeile (Wiedergabe, Zeitleiste, Zeit, Lautstärke, Geschwindigkeit), eine Variante `mini` für Tabellen und Listen, eine im Browser berechnete Wellenform und eine Playlist. Den Controller teilt er mit [UidVideo](./video.md).

```vue
<UidAudio src="/media/episode.mp3" title="Episode 12" artist="The Podcast" waveform />

<UidAudio :src="row.recording" variant="mini" />

<UidAudio v-model:index="current" :tracks="playlist" waveform />
```

| Prop | Typ | Standard | |
|---|---|---|---|
| `src`, `type` | `string` | — | Ein Titel; mit `type` wird ein nicht abspielbares Format sofort gemeldet |
| `title`, `artist` | `string` | — | Über der Zeitleiste angezeigt |
| `tracks` | `UidAudioTrack[]` | — | Playlist: `{ src, type?, title?, artist?, peaks?, duration? }` |
| `index` (`v-model:index`) | `number` | `0` | Aktueller Titel der Playlist |
| `variant` | `'default' \| 'mini'` | `'default'` | `mini` — eine Zeile: Wiedergabe, Leiste, Zeit |
| `waveform` | `boolean` | `false` | Im Browser dekodierte Wellenform als Zeitleiste |
| `peaks` | `number[]` | — | Vorberechnete Spitzen `0..1`; zeichnet die Wellenform ohne Dekodierung |
| `waveformMaxBytes` | `number` | 40 MB | Größere Dateien werden nicht dekodiert — stattdessen eine einfache Leiste |
| `waveformMaxDuration` | `number` | 1800 | Längeres Audio (Sekunden) wird nicht dekodiert |
| `autoAdvance` | `boolean` | `true` | Nächster Titel der Playlist, wenn einer endet |
| `loop` | `boolean` | `false` | Den Titel oder die ganze Playlist wiederholen |
| `preload` | `'none' \| 'metadata' \| 'auto'` | `'metadata'` | |
| `crossorigin` | `'' \| 'anonymous' \| 'use-credentials'` | — | |
| `exclusive` | `boolean` | `true` | Der Start dieses Players pausiert die anderen |
| `resumeKey` | `string` | — | Merkt sich die Position (je Titel der Playlist) |
| `rates` | `number[]` | `0.5…2` | Geschwindigkeitsmenü |
| `hotkeys` | `boolean` | `true` | Leertaste/`K`, Pfeiltasten, `J`/`L`, `M`, `0`–`9`; `Shift+N` / `Shift+P` — nächster / vorheriger Titel |
| `showVolume`, `showRate` | `boolean` | `true` | |
| `showPlaylist` | `boolean` | `true` | Titelliste unter dem Player |

Events: `play`, `pause`, `ended`, `error`, `trackchange` (Index), `update:index`. Die Props `hlsOptions` und `hlsLoader` funktionieren wie bei UidVideo. Bereitgestellt: `play()`, `pause()`, `toggle()`, `seek()`, `next()`, `prev()`, `state`, `media`.

## Layout

- **Standard** — eine Zeile: Wiedergabe-Button, Titel und Zeitleiste, Zeit, Lautstärke, Geschwindigkeit. In einem schmalen Container (unter 480 px) stehen Titel und Interpret untereinander und werden mit Auslassungspunkten gekürzt, die Zeitleiste wandert in eine eigene Zeile in voller Breite, die Zeit darunter, der Lautstärkeregler bleibt den Hardwaretasten überlassen. Ab 560 px ist der Lautstärkeregler immer sichtbar.
- **Mini** — standardmäßig `240px` breit (`--uid-audio-mini-width`), passt in eine Tabellenzelle: Wiedergabe, Leiste oder kleine Wellenform, Zeit (vor der Wiedergabe die Dauer, währenddessen die Position). Der Start einer Zeile pausiert die anderen.
- **Playlist** — Zurück / Weiter neben dem Wiedergabe-Button und eine nummerierte Liste mit markiertem laufendem Titel. „Zurück“ spult einen Titel, der länger als 3 Sekunden läuft, zuerst an den Anfang. Sperrbildschirm und Hardware-Medientasten funktionieren über die Media Session API. Die Dauern aller Titel werden nacheinander aus ihren Metadaten gelesen; bis dahin zeigt die Liste „—“.

## Wellenform

Mit `waveform` wird die Datei geladen und mit Web Audio dekodiert (`decodeAudioData` mit niedriger Abtastrate, um Speicher zu sparen), und die Spitzen werden in Portionen berechnet, zwischen denen der Browser zum Zug kommt (`requestIdleCallback`, sonst `setTimeout`). Ergebnisse werden je Adresse für die Lebensdauer der Seite zwischengespeichert; Dateien werden einzeln dekodiert und erst, wenn der Player nahe am Viewport ist, sodass eine Tabelle mit hundert Aufnahmen reaktionsschnell bleibt. Dateien über `waveformMaxBytes` oder länger als `waveformMaxDuration` behalten die einfache Leiste. Das Audio muss für `fetch` lesbar sein — gleicher Origin oder CORS. Bis die Spitzen fertig sind, zeigt die Leiste einen schimmernden Platzhalter statt einer einfachen Linie, die endgültig wirkt.

Für lange Aufnahmen die Spitzen auf dem Server berechnen und in `peaks` übergeben (beliebige Länge; der Player resampelt auf seine Breite):

```ts
import { computePeaks } from '@dskripchenko/ui'

// etwa in einem Worker oder bei der Verarbeitung eines Uploads
const peaks = await computePeaks([audioBuffer.getChannelData(0)], 512)
```

Helfer: `getWaveform(src, options)`, `computePeaks(channels, count)`, `resamplePeaks(peaks, n)`, `peaksToPath(peaks)`.

## HLS

Eine `.m3u8`-Quelle (oder `type: 'application/x-mpegURL'`) spielt über denselben bei Bedarf geladenen Adapter wie in [UidVideo](./video.md#hls): reine Audio-Master- oder Media-Playlists, Segmente in fMP4, MPEG-TS oder Packed AAC. Für Streams wird keine Wellenform gezeichnet.

## Formate

| Format | Chrome / Edge | Firefox | Safari macOS | Safari iOS |
|---|---|---|---|---|
| MP3 | ✓ | ✓ | ✓ | ✓ |
| AAC / M4A | ✓ | ✓ | ✓ | ✓ |
| Ogg · Opus | ✓ | ✓ | ✓ (neuere Versionen) | ✓ (neuere Versionen) |
| Ogg · Vorbis | ✓ | ✓ | neuere Versionen | neuere Versionen |
| WAV (PCM) | ✓ | ✓ | ✓ | ✓ |
| FLAC | ✓ | ✓ | ✓ | ✓ |
| WebM · Opus | ✓ | ✓ | ✓ | ✓ (neuere Versionen) |

In echten Browsern geprüft (Playwright): MP3, Ogg/Opus, WAV, FLAC und M4A werden in Chromium 156, Chrome 156 und WebKit 27 abgespielt und zeichnen die Wellenform. Bei einem weniger verbreiteten Format besser `type` angeben: Der Player meldet „nicht unterstützt“ sofort statt erst nach einem fehlgeschlagenen Laden.

## Gestaltung

Variablen: `--uid-audio-accent`, `--uid-audio-accent-hover`, `--uid-audio-bg`, `--uid-audio-border`, `--uid-audio-radius`, `--uid-audio-padding`, `--uid-audio-play-size`, `--uid-audio-play-color`, `--uid-audio-wave`, `--uid-audio-wave-height`, `--uid-audio-mini-width`, `--uid-audio-list-max-height`.
3 changes: 2 additions & 1 deletion docs/de/i18n.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ provideLocale(computed(() => (lang.value === 'ru' ? ru : en)))

Alle Komponenten-Texte (Platzhalter, ARIA-Labels, Buttontext) werden über den Provider lokalisiert. Abgedeckte Komponenten:

Select, Combobox, DatePicker, DateRangePicker, TimePicker, TreeSelect, NumberInput, TagsInput, FileUpload, Mention, BackTop, Tour, TreeView, Pagination, Modal, Drawer, Toast, Alert, Tag, Code, DescriptionList, ColorPicker, Cascader, Calendar u. a.
Select, Combobox, DatePicker, DateRangePicker, TimePicker, TreeSelect, NumberInput, TagsInput, FileUpload, Mention, BackTop, Tour, TreeView, Pagination, Modal, Drawer, Toast, Alert, Tag, Code, DescriptionList, ColorPicker, Cascader, Calendar, Video, Audio u. a.

## Per-Prop-Überschreibungen

Expand Down Expand Up @@ -192,6 +192,7 @@ interface UidLocale {
modal: { close: string }
drawer: { close: string }
toast: { close: string }
media?: UidMediaLocale // UidVideo, UidAudio: buttons, menus, errors
breadcrumb?: { showHidden: string }
pagination: {
first: string; prev: string; next: string; last: string
Expand Down
Loading
Loading