Add multi-language audio tracks and self-hosted flag-icons

Introduce per-video language support and multiple audio tracks
(VideoAudioTrack model + migrations for language, description, title),
a reusable language-select component, and a track-editor form. Bundle
the self-hosted flag-icons v7.2.3 library and a NAS auto-sync command.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
This commit is contained in:
ghassanandClaude Opus 4.7 committed 2026-05-22 21:32:52 +03:00
1 parent f8d13457fa
commit 66fd78c10f
314 files changed
+16507 -3172

No files matched your search

+58 -5
View File
@@ -1,13 +1,13 @@
# Reusable Select Component Usage
This file tracks every page/partial that uses `<x-phone-code-select>`, `<x-country-select>`, or `<x-timezone-select>`.
This file tracks every page/partial that uses `<x-phone-code-select>`, `<x-country-select>`, `<x-timezone-select>`, or `<x-language-select>`.
**Update this file whenever you add or remove a component from a view.**
When modifying any component or its data source (`app/Data/Countries.php`), check all pages in the relevant section below and verify the change works correctly in each context.
When modifying any component or its data source, check all pages in the relevant section below and verify the change works correctly in each context.
---
## Data source
## Data sources
**`app/Data/Countries.php`** — `App\Data\Countries`
@@ -20,18 +20,30 @@ When modifying any component or its data source (`app/Data/Countries.php`), chec
Adding or renaming a field in `Countries::all()` requires updating the corresponding `for*()` method too.
**`app/Data/Languages.php`** — `App\Data\Languages`
| Method | Used by component |
|---|---|
| `Languages::forLanguage()` | `<x-language-select>` |
| `Languages::all()` | Via `forLanguage()` |
Arabic and English are pinned to the top of the list; all others are sorted alphabetically by English name. Stored value is the ISO 639-1 code (e.g. `"ar"`, `"en"`).
---
## Shared CSS / JS
The `.csd-*` CSS rules and the `window.CSD` class are duplicated across all three component files inside `@once` guards. If you change the look or behaviour of the dropdown, **update all three component files**:
The `.csd-*` CSS rules and the `window.CSD` class are duplicated across all four component files inside `@once` guards. If you change the look or behaviour of the dropdown, **update all four component files**:
- `resources/views/components/phone-code-select.blade.php`
- `resources/views/components/country-select.blade.php`
- `resources/views/components/timezone-select.blade.php`
- `resources/views/components/language-select.blade.php`
The `@once` Blade directive ensures the browser only receives one copy of the CSS/JS even when multiple components are on the same page.
`language-select` also emits an extra `@once('lsd-badge-styles')` block for the `.lsd-code` ISO badge that appears in place of a flag emoji.
---
## `<x-video-insights>`
@@ -88,7 +100,7 @@ The `@once` Blade directive ensures the browser only receives one copy of the CS
| `resources/views/user/channel.blade.php` | `avatar` — circle 300×300 | Owner only; `update-url = profile.updateAvatar`; callback `onAvatarSaved` |
| `resources/views/user/channel.blade.php` | `banner` — square 500×160 | Owner only; `update-url = profile.updateBanner`; callback `onBannerSaved` |
| `resources/views/layouts/partials/upload-modal.blade.php` | `thumb_upload` — square 448×252 | Form mode; `target-input=thumbnail-modal`; output 1280px |
| `resources/views/layouts/partials/edit-video-modal.blade.php` | `thumb_edit` — square 448×252 | Form mode; `target-input=edit-thumbnail-input`; output 1280px |
| `resources/views/layouts/partials/edit-video-modal.blade.php` | `thumb_edit` — square 448×252 | Form mode; `target-input=edit-t1-thumbnail-input`; output 1280px |
| `resources/views/videos/create.blade.php` | `thumb_create_mobile` — square 448×252 | Mobile; `target-input=thumbnail`; output 1280px |
| `resources/views/videos/edit.blade.php` | `thumb_edit_mobile` — square 448×252 | Mobile; `target-input=edit-thumbnail`; output 1280px |
| `resources/views/playlists/index.blade.php` | `thumb_pl_create` — square 448×252 | Form mode; `target-input=playlist-thumbnail-input`; output 1280px |
@@ -140,6 +152,38 @@ Stored value: IANA timezone string (e.g. `"Asia/Bahrain"`).
---
## `<x-track-editor-form>`
**File:** `resources/views/components/track-editor-form.blade.php`
**Props:** `prefix` (default `'t1'`), `isPrimary` (bool, default `false`), `languageName`, `languageId`, `titleName`, `titleId`, `descName`, `descId`, `videoFileInputId`.
**Behaviour:** Renders the full track editor form panel shown inside the Track Editor popup. Contains: optional Primary Track banner (when `:is-primary="true"`), language dropdown (`<x-language-select>`), title input, description textarea, video+thumbnail zone (hidden, shown for video/match type via `_editApplyMode`), and audio+slides zone (hidden, shown for music type). All element IDs are prefixed with `edit-{prefix}-*`. JS functions `editHandleThumbnail(input, prefix)`, `editRemoveThumbnail(event, prefix)`, `editSlidesZoneClick(event, tid)`, `editHandleSlides(files, tid)`, `editClearSlides(event, tid)` all accept the prefix/tid param.
| View file | Prefix used | Notes |
|---|---|---|
| `resources/views/layouts/partials/edit-video-modal.blade.php` | `t1` | Primary track only; secondary tracks are built via JS (`_editAddExistingTrack`) |
---
## `<x-language-select>`
**File:** `resources/views/components/language-select.blade.php`
**Data source:** `app/Data/Languages.php` — `Languages::forLanguage()`
**Stored value:** ISO 639-1 code (e.g. `"ar"`, `"en"`, `"fr"`).
**Props:** `name`, `id`, `value`, `label`, `placeholder`, `required`, `class`, `style`.
**Icon:** 2-letter uppercase ISO code rendered as a monospace badge (`.lsd-code`) — no flag emoji.
**Arabic and English are always pinned to the top** of the list; all other languages are alphabetical by English name.
**Rule:** This component must be used for every language picker in the application. Never build a custom `<select>` or inline list for language selection.
| View file | Field name | Notes |
|---|---|---|
| `resources/views/layouts/partials/upload-modal.blade.php` | `primary_language` | Inside accordion track 1 body (`id="lang-tracks-section-modal"`); extra track language rows use `LANG_OPTIONS_MODAL` JS constant for inline dynamic CSD |
| `resources/views/videos/create.blade.php` | `primary_language` | Inside accordion track 1 body (`id="lang-tracks-section-create"`); extra track language rows use `LANG_OPTIONS_CREATE` JS constant for inline dynamic CSD |
| `resources/views/components/track-editor-form.blade.php` | `$languageName` (prop) | Rendered inside the track editor form; used for primary track in edit-video-modal (prefix `t1`) |
| `resources/views/videos/edit.blade.php` | `primary_language` | Inside `@else` (audio only) block; pre-populated with `value="{{ $video->language ?? '' }}"` |
---
## Usage example
```blade
@@ -171,6 +215,15 @@ Stored value: IANA timezone string (e.g. `"Asia/Bahrain"`).
value="{{ old('timezone', $user->timezone ?? 'Asia/Bahrain') }}"
required
/>
{{-- Language --}}
<x-language-select
name="language"
label="Language"
placeholder="Select language"
value="{{ old('language', $video->language ?? '') }}"
required
/>
```
---