Skip to content

Commit 773d131

Browse files
committed
feat(player): more settings for default layout
1 parent 5f1d317 commit 773d131

File tree

7 files changed

+185
-46
lines changed

7 files changed

+185
-46
lines changed

packages/vidstack/src/components/layouts/default/props.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,17 @@ export const defaultLayoutProps: DefaultLayoutProps = {
1010
disableTimeSlider: false,
1111
menuContainer: null,
1212
menuGroup: 'bottom',
13+
flatSettingsMenu: false,
1314
noAudioGain: false,
15+
noAudioTracks: false,
16+
noMediaLoop: false,
17+
noMediaSpeed: false,
18+
noMediaQuality: false,
1419
noGestures: false,
20+
noAnnouncements: false,
1521
noKeyboardAnimations: false,
22+
noCaptionStyles: false,
23+
noCaptions: false,
1624
noModal: false,
1725
noScrubGesture: false,
1826
playbackRates: { min: 0, max: 2, step: 0.25 },
@@ -71,10 +79,30 @@ export interface DefaultLayoutProps {
7179
* only applies to the large video layout.
7280
*/
7381
menuGroup: 'top' | 'bottom';
82+
/**
83+
* Do not split settings menu into submenus
84+
*/
85+
flatSettingsMenu: boolean;
7486
/**
7587
* Disable audio boost slider in the settings menu.
7688
*/
7789
noAudioGain: boolean;
90+
/**
91+
* Disable audio tracks in the settings menu.
92+
*/
93+
noAudioTracks: boolean;
94+
/**
95+
* Disable loop switch in the settings menu.
96+
*/
97+
noMediaLoop: boolean;
98+
/**
99+
* Disable media speed slider in the settings menu.
100+
*/
101+
noMediaSpeed: boolean;
102+
/**
103+
* Disable media quality slider in the settings menu.
104+
*/
105+
noMediaQuality: boolean;
78106
/**
79107
* Whether modal menus should be disabled when the small layout is active. A modal menu is
80108
* a floating panel that floats up from the bottom of the screen (outside of the player). It's
@@ -97,10 +125,22 @@ export interface DefaultLayoutProps {
97125
* Whether all gestures such as press to play or seek should not be active.
98126
*/
99127
noGestures: boolean;
128+
/**
129+
* Whether announcements should not be displayed.
130+
*/
131+
noAnnouncements: boolean;
100132
/**
101133
* Whether keyboard actions should not be displayed.
102134
*/
103135
noKeyboardAnimations: boolean;
136+
/**
137+
* Whether caption styles should not be displayed.
138+
*/
139+
noCaptionStyles: boolean;
140+
/**
141+
* Whether captions should not be displayed.
142+
*/
143+
noCaptions: boolean;
104144
/**
105145
* Whether the bitrate should be hidden in the settings quality hint.
106146
*

packages/vidstack/src/components/ui/menu/menu.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,8 @@ export class Menu extends Component<MenuProps, {}, MenuEvents> {
519519
#onResize = animationFrameThrottle(() => {
520520
const content = peek(this.#content);
521521
if (!content || __SERVER__) return;
522+
// Disable resize for flatSettingsMenu because it works wrong with DefaultFontMenu()
523+
if (content.getAttribute('flat') == 'true') return;
522524

523525
let height = 0,
524526
styles = getComputedStyle(content),

packages/vidstack/src/elements/define/layouts/default/ui/menu/accessibility-menu.ts

Lines changed: 60 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,72 @@ import { DefaultMenuButton, DefaultMenuItem, DefaultMenuSection } from './items/
1212

1313
export function DefaultAccessibilityMenu() {
1414
return $signal(() => {
15-
const { translations } = useDefaultLayoutContext();
15+
const {
16+
flatSettingsMenu,
17+
noAnnouncements,
18+
noKeyboardAnimations,
19+
noCaptionStyles,
20+
translations,
21+
} = useDefaultLayoutContext();
22+
23+
if (flatSettingsMenu()) {
24+
const items: any[] = [];
25+
if (!noAnnouncements()) {
26+
items.push(DefaultAnnouncementsMenuCheckbox());
27+
}
28+
if (!noKeyboardAnimations()) {
29+
items.push(DefaultKeyboardAnimationsMenuCheckbox());
30+
}
31+
if (!noCaptionStyles()) {
32+
items.push(DefaultFontMenu());
33+
}
34+
35+
return items.length
36+
? DefaultMenuSection({
37+
label: i18n(translations, 'Accessibility'),
38+
children: items,
39+
})
40+
: null;
41+
}
42+
43+
const items: any[] = [];
44+
const topItems: any[] = [];
45+
const bottomItems: any[] = [];
46+
47+
if (!noAnnouncements()) {
48+
topItems.push(DefaultAnnouncementsMenuCheckbox());
49+
}
50+
if (!noKeyboardAnimations()) {
51+
topItems.push(DefaultKeyboardAnimationsMenuCheckbox());
52+
}
53+
if (!noCaptionStyles()) {
54+
bottomItems.push(DefaultFontMenu());
55+
}
56+
57+
if (topItems.length) {
58+
items.push(
59+
DefaultMenuSection({
60+
children: topItems,
61+
}),
62+
);
63+
}
64+
if (bottomItems.length) {
65+
items.push(
66+
DefaultMenuSection({
67+
children: bottomItems,
68+
}),
69+
);
70+
}
71+
72+
if (!items.length) return null;
73+
1674
return html`
1775
<media-menu class="vds-accessibility-menu vds-menu">
1876
${DefaultMenuButton({
1977
label: () => i18n(translations, 'Accessibility'),
2078
icon: 'menu-accessibility',
2179
})}
22-
<media-menu-items class="vds-menu-items">
23-
${[
24-
DefaultMenuSection({
25-
children: [
26-
DefaultAnnouncementsMenuCheckbox(),
27-
DefaultKeyboardAnimationsMenuCheckbox(),
28-
],
29-
}),
30-
DefaultMenuSection({
31-
children: [DefaultFontMenu()],
32-
}),
33-
]}
34-
</media-menu-items>
80+
<media-menu-items class="vds-menu-items"> ${items} </media-menu-items>
3581
</media-menu>
3682
`;
3783
});

packages/vidstack/src/elements/define/layouts/default/ui/menu/audio-menu.ts

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ import { DefaultMenuSliderItem, DefaultSliderParts, DefaultSliderSteps } from '.
1212

1313
export function DefaultAudioMenu() {
1414
return $signal(() => {
15-
const { noAudioGain, translations } = useDefaultLayoutContext(),
15+
const { flatSettingsMenu, noAudioGain, noAudioTracks, translations } =
16+
useDefaultLayoutContext(),
1617
{ audioTracks, canSetAudioGain } = useMediaState(),
1718
$disabled = computed(() => {
1819
const hasGainSlider = canSetAudioGain() && !noAudioGain();
@@ -21,15 +22,33 @@ export function DefaultAudioMenu() {
2122

2223
if ($disabled()) return null;
2324

25+
const items: any[] = [];
26+
if (!noAudioGain()) {
27+
items.push(DefaultAudioBoostSection());
28+
}
29+
if (!noAudioTracks()) {
30+
items.push(DefaultAudioTracksMenu());
31+
}
32+
33+
if (!items.length) {
34+
return null;
35+
}
36+
37+
if (flatSettingsMenu())
38+
return [
39+
DefaultMenuSection({
40+
label: i18n(translations, 'Audio'),
41+
children: items,
42+
}),
43+
];
44+
2445
return html`
2546
<media-menu class="vds-audio-menu vds-menu">
2647
${DefaultMenuButton({
2748
label: () => i18n(translations, 'Audio'),
2849
icon: 'menu-audio',
2950
})}
30-
<media-menu-items class="vds-menu-items">
31-
${[DefaultAudioTracksMenu(), DefaultAudioBoostSection()]}
32-
</media-menu-items>
51+
<media-menu-items class="vds-menu-items"> ${items} </media-menu-items>
3352
</media-menu>
3453
`;
3554
});
@@ -119,13 +138,13 @@ function DefaultAudioGainSlider() {
119138
function getGainMin() {
120139
const { audioGains } = useDefaultLayoutContext(),
121140
gains = audioGains();
122-
return isArray(gains) ? gains[0] ?? 0 : gains.min;
141+
return isArray(gains) ? (gains[0] ?? 0) : gains.min;
123142
}
124143

125144
function getGainMax() {
126145
const { audioGains } = useDefaultLayoutContext(),
127146
gains = audioGains();
128-
return isArray(gains) ? gains[gains.length - 1] ?? 300 : gains.max;
147+
return isArray(gains) ? (gains[gains.length - 1] ?? 300) : gains.max;
129148
}
130149

131150
function getGainStep() {

packages/vidstack/src/elements/define/layouts/default/ui/menu/captions-menu.ts

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,36 +5,50 @@ import { i18n } from '../../../../../../components/layouts/default/translations'
55
import { useMediaState } from '../../../../../../core/api/media-context';
66
import { $signal } from '../../../../../lit/directives/signal';
77
import { $i18n } from '../utils';
8-
import { DefaultMenuButton } from './items/menu-items';
8+
import { DefaultMenuButton, DefaultMenuSection } from './items/menu-items';
99

1010
export function DefaultCaptionsMenu() {
1111
return $signal(() => {
12-
const { translations } = useDefaultLayoutContext(),
13-
{ hasCaptions } = useMediaState(),
14-
$offText = $i18n(translations, 'Off');
12+
const { flatSettingsMenu, noCaptions, translations } = useDefaultLayoutContext(),
13+
{ hasCaptions } = useMediaState();
1514

16-
if (!hasCaptions()) return null;
15+
if (!hasCaptions() || noCaptions()) return null;
16+
17+
if (flatSettingsMenu())
18+
return [
19+
DefaultMenuSection({
20+
label: i18n(translations, 'Captions'),
21+
children: [DefaultCaptionsMenuItems()],
22+
}),
23+
];
1724

1825
return html`
1926
<media-menu class="vds-captions-menu vds-menu">
2027
${DefaultMenuButton({
2128
label: () => i18n(translations, 'Captions'),
2229
icon: 'menu-captions',
2330
})}
24-
<media-menu-items class="vds-menu-items">
25-
<media-captions-radio-group
26-
class="vds-captions-radio-group vds-radio-group"
27-
off-label=${$offText}
28-
>
29-
<template>
30-
<media-radio class="vds-caption-radio vds-radio">
31-
<slot name="menu-radio-check-icon" data-class="vds-icon"></slot>
32-
<span class="vds-radio-label" data-part="label"></span>
33-
</media-radio>
34-
</template>
35-
</media-captions-radio-group>
36-
</media-menu-items>
31+
<media-menu-items class="vds-menu-items"> ${DefaultCaptionsMenuItems()} </media-menu-items>
3732
</media-menu>
3833
`;
3934
});
4035
}
36+
37+
function DefaultCaptionsMenuItems() {
38+
const { translations } = useDefaultLayoutContext(),
39+
$offText = $i18n(translations, 'Off');
40+
41+
return html`
42+
<media-captions-radio-group
43+
class="vds-captions-radio-group vds-radio-group"
44+
off-label=${$offText}
45+
>
46+
<template>
47+
<media-radio class="vds-caption-radio vds-radio">
48+
<slot name="menu-radio-check-icon" data-class="vds-icon"></slot>
49+
<span class="vds-radio-label" data-part="label"></span>
50+
</media-radio>
51+
</template>
52+
</media-captions-radio-group>
53+
`;
54+
}

packages/vidstack/src/elements/define/layouts/default/ui/menu/playback-menu.ts

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,37 @@ import { DefaultMenuSliderItem, DefaultSliderParts, DefaultSliderSteps } from '.
1414

1515
export function DefaultPlaybackMenu() {
1616
return $signal(() => {
17-
const { translations } = useDefaultLayoutContext();
17+
const { flatSettingsMenu, noMediaLoop, noMediaSpeed, noMediaQuality, translations } =
18+
useDefaultLayoutContext();
19+
20+
const items: any[] = [];
21+
22+
if (!noMediaLoop()) {
23+
items.push(
24+
DefaultMenuSection({
25+
children: DefaultLoopCheckbox(),
26+
}),
27+
);
28+
}
29+
if (!noMediaSpeed()) {
30+
items.push(DefaultSpeedMenuSection());
31+
}
32+
if (!noMediaQuality()) {
33+
items.push(DefaultQualityMenuSection());
34+
}
35+
36+
if (!items.length) return null;
37+
38+
if (flatSettingsMenu()) return items;
39+
1840
return html`
1941
<media-menu class="vds-playback-menu vds-menu">
2042
${DefaultMenuButton({
2143
label: () => i18n(translations, 'Playback'),
2244
icon: 'menu-playback',
2345
})}
2446
<media-menu-items class="vds-menu-items">
25-
${[
26-
DefaultMenuSection({
27-
children: DefaultLoopCheckbox(),
28-
}),
29-
DefaultSpeedMenuSection(),
30-
DefaultQualityMenuSection(),
31-
]}
47+
${items}
3248
</media-menu-items>
3349
</media-menu>
3450
`;

packages/vidstack/src/elements/define/layouts/default/ui/menu/settings-menu.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export function DefaultSettingsMenu({
3232
menuPortal,
3333
noModal,
3434
menuGroup,
35+
flatSettingsMenu,
3536
smallWhen: smWhen,
3637
} = useDefaultLayoutContext(),
3738
$placement = computed(() =>
@@ -57,6 +58,7 @@ export function DefaultSettingsMenu({
5758
class="vds-settings-menu-items vds-menu-items"
5859
placement=${$signal($placement)}
5960
offset=${$signal($offset)}
61+
flat="${flatSettingsMenu()}"
6062
>
6163
${$signal(() => {
6264
if (!$isOpen()) {

0 commit comments

Comments
 (0)