@cinecrew/cinecrew-player 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/native/InlineLivePlayer.js +1 -1
- package/src/native/MediaPlayerView.js +1 -1
- package/src/native/customization.js +2 -1
- package/src/native/media/player/PlayerBottomBar.js +2 -2
- package/src/native/media/player/PlayerTopBar.js +1 -1
- package/src/native/media/web/useWebVideoAspectRatio.js +11 -1
- package/src/web/index.js +146 -41
- package/src/web/styles.css +163 -31
package/package.json
CHANGED
|
@@ -117,7 +117,7 @@ function InlinePlayerOverlay({
|
|
|
117
117
|
palette,
|
|
118
118
|
});
|
|
119
119
|
const muteLabel = muted ? 'Unmute' : 'Mute';
|
|
120
|
-
const muteIcon = muted ? '
|
|
120
|
+
const muteIcon = muted ? 'mute' : 'unmute';
|
|
121
121
|
const playbackLabel = paused ? 'Play' : 'Pause';
|
|
122
122
|
const playbackIcon = paused ? 'play' : 'pause';
|
|
123
123
|
|
|
@@ -360,7 +360,7 @@ function InlinePreviewTopActions({ controls, muted, videoOnlyMode, handleMuteAct
|
|
|
360
360
|
handleMuteAction();
|
|
361
361
|
}}
|
|
362
362
|
>
|
|
363
|
-
<PlayerIcon name={muted || videoOnlyMode ? '
|
|
363
|
+
<PlayerIcon name={muted || videoOnlyMode ? 'mute' : 'unmute'} size={19} color="#FFF" />
|
|
364
364
|
</TouchableOpacity>
|
|
365
365
|
) : null}
|
|
366
366
|
</View>
|
|
@@ -40,5 +40,6 @@ export function PlayerIcon({ name, pack = 'community', size = 20, color = '#FFFF
|
|
|
40
40
|
return React.createElement(Text, { style: [{ fontSize: size, color }, style], accessibilityElementsHidden: true }, custom);
|
|
41
41
|
}
|
|
42
42
|
const IconSet = pack === 'material' ? MaterialIcons : MaterialCommunityIcons;
|
|
43
|
-
|
|
43
|
+
const defaultIconNames = { mute: 'volume-off', unmute: 'volume-high' };
|
|
44
|
+
return React.createElement(IconSet, { name: typeof custom === 'string' ? custom : (defaultIconNames[name] || name), size, color, style });
|
|
44
45
|
}
|
|
@@ -53,7 +53,7 @@ function AudioOnlyModeControl({ isAudioOnly, onToggle }) {
|
|
|
53
53
|
function VideoOnlyControl({ isVideoOnly, onToggle }) {
|
|
54
54
|
const palette = usePlayerColors();
|
|
55
55
|
const selectedStyle = isVideoOnly ? { backgroundColor: palette.surfaceColor, borderWidth: 1.5, borderColor: palette.accentColor } : null;
|
|
56
|
-
return <TouchableOpacity style={[styles.speedButton, { backgroundColor: palette.controlBackground }, selectedStyle]} onPress={(event) => { event.stopPropagation(); onToggle?.(); }} accessibilityLabel={isVideoOnly ? '
|
|
56
|
+
return <TouchableOpacity style={[styles.speedButton, { backgroundColor: palette.controlBackground }, selectedStyle]} onPress={(event) => { event.stopPropagation(); onToggle?.(); }} accessibilityLabel={isVideoOnly ? 'Disable video-only mode' : 'Video only'}><PlayerIcon name="video" size={18} color={isVideoOnly ? palette.accentColor : palette.controlColor} /></TouchableOpacity>;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
function SpeedControl({ enabled, open, playbackRate, onToggle, onSelect }) {
|
|
@@ -81,7 +81,7 @@ function SpeedControl({ enabled, open, playbackRate, onToggle, onSelect }) {
|
|
|
81
81
|
|
|
82
82
|
function AudioTrackMenu({ open, audioTracks, selectedAudioTrack, onSelect, palette }) {
|
|
83
83
|
if (!open) return null;
|
|
84
|
-
if (audioTracks.length
|
|
84
|
+
if (audioTracks.length === 0) return <View style={[styles.speedPickerPopup, { backgroundColor: palette.surfaceColor, borderColor: palette.borderColor }]}><Text style={[styles.speedOptionText, { color: palette.controlColor }]}>No audio tracks available</Text></View>;
|
|
85
85
|
return (
|
|
86
86
|
<View style={[styles.speedPickerPopup, { backgroundColor: palette.surfaceColor, borderColor: palette.borderColor }]}>
|
|
87
87
|
<Text style={[styles.speedPickerTitle, { color: palette.mutedColor }]}>Audio</Text>
|
|
@@ -60,7 +60,7 @@ function PlaybackSessionControls({ isLive, controls, muted, onRestart, onMute, o
|
|
|
60
60
|
return (
|
|
61
61
|
<>
|
|
62
62
|
{!isLive && controls.restart !== false ? <TouchableOpacity style={styles.pill} onPress={(event) => { event.stopPropagation(); onRestart(); }} hitSlop={12}><PlayerIcon name="restart" size={20} color={palette.controlColor} /></TouchableOpacity> : null}
|
|
63
|
-
{controls.mute !== false ? <TouchableOpacity style={styles.pill} onPress={(event) => { event.stopPropagation(); onMute(); }} hitSlop={12}><PlayerIcon name={muted ? '
|
|
63
|
+
{controls.mute !== false ? <TouchableOpacity style={styles.pill} onPress={(event) => { event.stopPropagation(); onMute(); }} hitSlop={12}><PlayerIcon name={muted ? 'mute' : 'unmute'} size={20} color={muted ? palette.errorColor : palette.controlColor} /></TouchableOpacity> : null}
|
|
64
64
|
{controls.lock !== false ? <TouchableOpacity style={styles.pill} onPress={(event) => { event.stopPropagation(); onLock(); }} hitSlop={12}><PlayerIcon name="lock-open-variant" size={20} color={palette.controlColor} /></TouchableOpacity> : null}
|
|
65
65
|
</>
|
|
66
66
|
);
|
|
@@ -36,7 +36,17 @@ export function useWebVideoAspectRatio(videoAspectRatio, audioOnly) {
|
|
|
36
36
|
width: useCustomRatio ? 'auto' : '100%',
|
|
37
37
|
height: useCustomRatio ? 'auto' : '100%',
|
|
38
38
|
...(useCustomRatio
|
|
39
|
-
? {
|
|
39
|
+
? {
|
|
40
|
+
position: 'absolute',
|
|
41
|
+
left: '50%',
|
|
42
|
+
top: '50%',
|
|
43
|
+
right: 'auto',
|
|
44
|
+
bottom: 'auto',
|
|
45
|
+
transform: 'translate(-50%, -50%)',
|
|
46
|
+
maxWidth: '100%',
|
|
47
|
+
maxHeight: '100%',
|
|
48
|
+
aspectRatio: aspectRatioVal,
|
|
49
|
+
}
|
|
40
50
|
: {}),
|
|
41
51
|
objectFit: useCustomRatio ? 'contain' : aspectFit,
|
|
42
52
|
backgroundColor: '#000',
|
package/src/web/index.js
CHANGED
|
@@ -21,7 +21,7 @@ const DEFAULT_THEME = {
|
|
|
21
21
|
const DEFAULT_ICONS = {
|
|
22
22
|
play: 'play', pause: 'pause', restart: 'restart', lock: 'lock', unlock: 'lock-open',
|
|
23
23
|
mute: 'volume-mute', unmute: 'volume-high', aspectRatio: 'aspect-ratio', videoOnly: 'video',
|
|
24
|
-
audio: 'music-note', back: 'arrow-left', recording: 'record-rec', stop: 'stop',
|
|
24
|
+
audio: 'music-note', audioOnly: 'headphones', back: 'arrow-left', recording: 'record-rec', stop: 'stop',
|
|
25
25
|
liveChat: 'comment-text-multiple-outline', epg: 'television-classic', diagnostics: 'logs',
|
|
26
26
|
fullscreen: 'fullscreen', close: 'close',
|
|
27
27
|
};
|
|
@@ -34,11 +34,12 @@ const WEB_ICON_PATHS = {
|
|
|
34
34
|
restart: 'M12 5V1L7 6l5 5V7a6 6 0 1 1-5.65 8H4.26A9 9 0 1 0 12 5z',
|
|
35
35
|
lock: 'M18 8h-1V6a5 5 0 0 0-10 0v2H6a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2zM9 6a3 3 0 0 1 6 0v2H9zm3 11a2 2 0 1 1 0-4 2 2 0 0 1 0 4z',
|
|
36
36
|
'lock-open': 'M18 8h-1V6a5 5 0 0 0-9.8-1H9a3 3 0 0 1 6 .8V8H6a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2zm-6 9a2 2 0 1 1 0-4 2 2 0 0 1 0 4z',
|
|
37
|
-
'volume-mute': 'M3 9v6h4l5 5V4L7 9H3zm13.
|
|
37
|
+
'volume-mute': 'M3 9v6h4l5 5V4L7 9H3zm13.59 3 2.12-2.12 1.41 1.41L19 13.41l2.12 2.12-1.41 1.41-2.12-2.12-2.12 2.12-1.41-1.41 2.12-2.12-2.12-2.12 1.41-1.41z',
|
|
38
38
|
'volume-high': 'M3 9v6h4l5 5V4L7 9H3zm13.5 3a4.5 4.5 0 0 0-2.5-4.03v8.05A4.5 4.5 0 0 0 16.5 12zM14 3.23v2.06a7 7 0 0 1 0 13.42v2.06a9 9 0 0 0 0-17.54z',
|
|
39
39
|
'aspect-ratio': 'M3 5h18v14H3zm2 2v10h14V7zm2 2h4v2H9v4H7zm10 6h-4v-2h2V9h2z',
|
|
40
40
|
video: 'M18 7V5a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2l4 4V5zm-2 12H4V5h12z',
|
|
41
41
|
'music-note': 'M12 3v12.26A4 4 0 1 0 14 19V7h6V3z',
|
|
42
|
+
headphones: 'M12 3a9 9 0 0 0-9 9v6a3 3 0 0 0 3 3h3v-9H5v-1a7 7 0 0 1 14 0v1h-4v9h3a3 3 0 0 0 3-3v-6a9 9 0 0 0-9-9z',
|
|
42
43
|
'arrow-collapse': 'M4 4h6v2H6v4H4zm10 0h6v6h-2V6h-4zM4 14h2v4h4v2H4zm14 0h2v6h-6v-2h4z',
|
|
43
44
|
logs: 'M3 3h18v18H3zm2 2v14h14V5zm3 3h2v2H8zm4 0h7v2h-7zm-4 4h2v2H8zm4 0h7v2h-7zm-4 4h2v2H8zm4 0h7v2h-7z',
|
|
44
45
|
'arrow-left': 'M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20z',
|
|
@@ -48,6 +49,13 @@ const WEB_ICON_PATHS = {
|
|
|
48
49
|
'television-classic': 'M21 3H3a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2h7v2h4v-2h7a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2zm0 15H3V5h18zM5 7h14v9H5z',
|
|
49
50
|
fullscreen: 'M4 4h6v2H6v4H4zm10 0h6v6h-2V6h-4zM4 14h2v4h4v2H4zm14 0h2v6h-6v-2h4z',
|
|
50
51
|
close: 'M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z',
|
|
52
|
+
send: 'M2 21 23 12 2 3v7l15 2-15 2z',
|
|
53
|
+
network: 'M12 2a3 3 0 1 0 0 6 3 3 0 0 0 0-6zM4 16a3 3 0 1 0 0 6 3 3 0 0 0 0-6zm16 0a3 3 0 1 0 0 6 3 3 0 0 0 0-6zM10.7 7.4 5.3 16.7l1.7 1 5.4-9.3zm2.6 0 5.4 9.3-1.7 1-5.4-9.3z',
|
|
54
|
+
speedometer: 'M12 3a9 9 0 1 0 9 9h-2a7 7 0 1 1-2.05-4.95l1.42-1.42A8.96 8.96 0 0 0 12 3zm7.7 1.3-6.4 6.4a2.5 2.5 0 1 0 1.4 1.4l6.4-6.4z',
|
|
55
|
+
buffer: 'M4 5h16v3H4zm0 5.5h16v3H4zm0 5.5h16v3H4z',
|
|
56
|
+
clock: 'M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20zm0 18a8 8 0 1 1 0-16 8 8 0 0 1 0 16zm1-13h-2v6l5 3 1-1.7-4-2.3z',
|
|
57
|
+
display: 'M3 4h18v13H3zm2 2v9h14V6zm5 13h4v2h-4z',
|
|
58
|
+
frames: 'M4 4h16v12H4zm2 2v8h12V6zm-4 13h16v2H2zm4-3h16v2H6z',
|
|
51
59
|
};
|
|
52
60
|
|
|
53
61
|
function getSource(source, url) {
|
|
@@ -119,44 +127,62 @@ function getPanelActionName(panel) {
|
|
|
119
127
|
function WebSeekControl({ currentTime, duration, theme, onSeek }) {
|
|
120
128
|
const [seekDraft, setSeekDraft] = useState(currentTime);
|
|
121
129
|
const [isDragging, setIsDragging] = useState(false);
|
|
130
|
+
const seekDraftRef = useRef(currentTime);
|
|
122
131
|
|
|
123
132
|
useEffect(() => {
|
|
124
|
-
if (!isDragging)
|
|
133
|
+
if (!isDragging) {
|
|
134
|
+
seekDraftRef.current = currentTime;
|
|
135
|
+
setSeekDraft(currentTime);
|
|
136
|
+
}
|
|
125
137
|
}, [currentTime, isDragging]);
|
|
126
138
|
|
|
127
|
-
const
|
|
139
|
+
const updateDraft = (event) => {
|
|
128
140
|
const nextTime = Number(event.currentTarget.value);
|
|
141
|
+
seekDraftRef.current = nextTime;
|
|
129
142
|
setSeekDraft(nextTime);
|
|
130
|
-
onSeek(nextTime);
|
|
131
143
|
};
|
|
132
144
|
|
|
133
145
|
const finishSeek = (event) => {
|
|
134
146
|
if (!isDragging) return;
|
|
135
|
-
|
|
147
|
+
const nextTime = event?.currentTarget && event.type !== 'blur'
|
|
148
|
+
? Number(event.currentTarget.value)
|
|
149
|
+
: seekDraftRef.current;
|
|
150
|
+
seekDraftRef.current = nextTime;
|
|
151
|
+
setSeekDraft(nextTime);
|
|
136
152
|
setIsDragging(false);
|
|
153
|
+
onSeek(nextTime);
|
|
137
154
|
};
|
|
155
|
+
const displayTime = Math.min(isDragging ? seekDraft : currentTime, duration);
|
|
156
|
+
const remainingTime = Math.max(0, duration - displayTime);
|
|
138
157
|
|
|
139
158
|
return h('div', { className: 'cinecrew-player__seek' },
|
|
140
|
-
h('span', null, formatTime(
|
|
159
|
+
h('span', null, formatTime(displayTime)),
|
|
141
160
|
h('input', {
|
|
142
161
|
type: 'range',
|
|
143
162
|
'aria-label': 'Seek video',
|
|
144
163
|
min: 0,
|
|
145
164
|
max: duration,
|
|
146
165
|
step: 'any',
|
|
147
|
-
value:
|
|
148
|
-
onChange:
|
|
166
|
+
value: displayTime,
|
|
167
|
+
onChange: updateDraft,
|
|
149
168
|
onPointerDown: (event) => {
|
|
150
169
|
event.stopPropagation();
|
|
151
170
|
setIsDragging(true);
|
|
152
|
-
|
|
171
|
+
seekDraftRef.current = Number(event.currentTarget.value);
|
|
172
|
+
setSeekDraft(seekDraftRef.current);
|
|
153
173
|
},
|
|
154
174
|
onPointerUp: finishSeek,
|
|
155
175
|
onPointerCancel: finishSeek,
|
|
156
176
|
onBlur: finishSeek,
|
|
177
|
+
onKeyDown: (event) => {
|
|
178
|
+
if (['ArrowLeft', 'ArrowRight', 'Home', 'End', 'PageUp', 'PageDown'].includes(event.key)) setIsDragging(true);
|
|
179
|
+
},
|
|
180
|
+
onKeyUp: (event) => {
|
|
181
|
+
if (['ArrowLeft', 'ArrowRight', 'Home', 'End', 'PageUp', 'PageDown'].includes(event.key)) finishSeek(event);
|
|
182
|
+
},
|
|
157
183
|
style: { accentColor: theme.accentColor },
|
|
158
184
|
}),
|
|
159
|
-
h('span', null, formatTime(
|
|
185
|
+
h('span', null, `−${formatTime(remainingTime)}`));
|
|
160
186
|
}
|
|
161
187
|
|
|
162
188
|
function WebAspectRatioMenu({ open, theme, icons, onToggle, onSelect }) {
|
|
@@ -179,11 +205,13 @@ function WebAudioTrackMenu({ open, tracks, theme, icons, onToggle, onSelect }) {
|
|
|
179
205
|
let menu = null;
|
|
180
206
|
if (open) {
|
|
181
207
|
menu = h('div', { className: 'cinecrew-player__menu', style: { background: theme.surfaceColor } },
|
|
182
|
-
tracks.
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
208
|
+
tracks.length
|
|
209
|
+
? tracks.map((track, index) => h('button', {
|
|
210
|
+
key: track.id ?? index,
|
|
211
|
+
type: 'button',
|
|
212
|
+
onClick: () => onSelect(track.id),
|
|
213
|
+
}, track.name || track.language || `Track ${index + 1}`))
|
|
214
|
+
: h('div', { className: 'cinecrew-player__menu-empty', role: 'status' }, 'No audio tracks available'));
|
|
187
215
|
}
|
|
188
216
|
return h('div', { className: 'cinecrew-player__menu-wrap', key: 'audioTracks' },
|
|
189
217
|
h(PlayerButton, { name: 'audio', label: 'Audio tracks', icons, theme, onClick: onToggle, active: open }),
|
|
@@ -226,7 +254,7 @@ function WebBottomControls(props) {
|
|
|
226
254
|
});
|
|
227
255
|
}
|
|
228
256
|
let audioTracks = null;
|
|
229
|
-
if (
|
|
257
|
+
if (isControlEnabled(overrides, 'audioTracks', true)) {
|
|
230
258
|
audioTracks = h(WebAudioTrackMenu, {
|
|
231
259
|
open: showAudioMenu,
|
|
232
260
|
tracks: availableTracks,
|
|
@@ -243,25 +271,25 @@ function WebBottomControls(props) {
|
|
|
243
271
|
if (isControlEnabled(overrides, 'playbackRate', true) && !isLive) {
|
|
244
272
|
playbackRateControl = h(WebPlaybackRateControl, { value: playbackRate, onChange: setPlaybackRateAction });
|
|
245
273
|
}
|
|
246
|
-
const videoOnlyLabel =
|
|
247
|
-
const audioOnlyLabel =
|
|
274
|
+
const videoOnlyLabel = 'Video only';
|
|
275
|
+
const audioOnlyLabel = 'Audio only';
|
|
248
276
|
const fullscreenLabel = fullscreen ? 'Exit full screen' : 'Full screen';
|
|
249
277
|
|
|
250
278
|
return h('div', { className: 'cinecrew-player__bottom-controls' },
|
|
251
279
|
seek,
|
|
252
280
|
h('div', { className: 'cinecrew-player__bottom-actions' },
|
|
253
281
|
h('div', { className: 'cinecrew-player__bottom-left-actions' },
|
|
282
|
+
renderControlButton({ name: 'audioOnly', label: audioOnlyLabel, callback: () => setAudioOnlyMode(true), options: { active: audioOnly }, overrides, icons, theme }),
|
|
254
283
|
renderControlButton({ name: 'videoOnly', label: videoOnlyLabel, callback: () => setVideoOnlyMode(!videoOnly), options: { active: videoOnly, defaultVisible: false }, overrides, icons, theme }),
|
|
255
284
|
aspect),
|
|
256
285
|
h('div', { className: 'cinecrew-player__bottom-right-actions' },
|
|
257
|
-
renderControlButton({ name: 'audioOnly', label: audioOnlyLabel, callback: () => setAudioOnlyMode(true), options: { icon: 'audio', active: audioOnly }, overrides, icons, theme }),
|
|
258
286
|
audioTracks,
|
|
259
287
|
playbackRateControl,
|
|
260
288
|
renderControlButton({ name: 'fullscreen', label: fullscreenLabel, callback: toggleFullscreen, options: { icon: 'fullscreen' }, overrides, icons, theme }))));
|
|
261
289
|
}
|
|
262
290
|
|
|
263
291
|
function WebPlayerControls({ locked, buffering, overrides, theme, icons, unlockedControls, toggleLock, paused, togglePlay, bottomProps }) {
|
|
264
|
-
let leftControls = unlockedControls.left;
|
|
292
|
+
let leftControls = locked ? null : unlockedControls.left;
|
|
265
293
|
let rightControls = unlockedControls.right;
|
|
266
294
|
if (locked) {
|
|
267
295
|
rightControls = renderControlButton({
|
|
@@ -330,10 +358,31 @@ function WebPlayerSurface({
|
|
|
330
358
|
onStateChange,
|
|
331
359
|
onError,
|
|
332
360
|
onEnded,
|
|
333
|
-
style: drawerResize ? { width: '64%', height: '
|
|
361
|
+
style: drawerResize ? { width: 'var(--cinecrew-media-width, 64%)', height: '100%', inset: '0 auto 0 0' } : undefined,
|
|
334
362
|
});
|
|
335
363
|
}
|
|
336
364
|
if (!streamUrl) return h('div', { className: 'cinecrew-player__empty' });
|
|
365
|
+
let resizedVideoStyle = {};
|
|
366
|
+
if (drawerResize && videoStyle.width === 'auto') {
|
|
367
|
+
resizedVideoStyle = {
|
|
368
|
+
left: 'calc(var(--cinecrew-media-width, 64%) / 2)',
|
|
369
|
+
top: '50%',
|
|
370
|
+
right: 'auto',
|
|
371
|
+
bottom: 'auto',
|
|
372
|
+
maxWidth: 'var(--cinecrew-media-width, 64%)',
|
|
373
|
+
transform: 'translate(-50%, -50%)',
|
|
374
|
+
};
|
|
375
|
+
} else if (drawerResize) {
|
|
376
|
+
resizedVideoStyle = {
|
|
377
|
+
width: 'var(--cinecrew-media-width, 64%)',
|
|
378
|
+
height: '100%',
|
|
379
|
+
left: 0,
|
|
380
|
+
top: 0,
|
|
381
|
+
right: 'auto',
|
|
382
|
+
bottom: 0,
|
|
383
|
+
transform: 'none',
|
|
384
|
+
};
|
|
385
|
+
}
|
|
337
386
|
return h('video', {
|
|
338
387
|
ref: videoRef,
|
|
339
388
|
className: 'cinecrew-player__video',
|
|
@@ -345,7 +394,7 @@ function WebPlayerSurface({
|
|
|
345
394
|
preload: 'auto',
|
|
346
395
|
style: {
|
|
347
396
|
...videoStyle,
|
|
348
|
-
...
|
|
397
|
+
...resizedVideoStyle,
|
|
349
398
|
opacity: audioOnly ? 0 : 1,
|
|
350
399
|
},
|
|
351
400
|
onClick: inlinePreview ? onPromotePreview : undefined,
|
|
@@ -357,12 +406,15 @@ function WebPlayerSurface({
|
|
|
357
406
|
});
|
|
358
407
|
}
|
|
359
408
|
|
|
360
|
-
function WebAudioOnlyCard({ poster, title, theme, onSwitchToVideo }) {
|
|
409
|
+
function WebAudioOnlyCard({ poster, title, theme, icons, onSwitchToVideo }) {
|
|
361
410
|
return h('div', {
|
|
362
411
|
className: 'cinecrew-player__audio-card',
|
|
363
412
|
style: { background: theme.surfaceColor, color: theme.controlColor, borderColor: theme.accentColor },
|
|
364
413
|
},
|
|
365
|
-
poster
|
|
414
|
+
poster
|
|
415
|
+
? h('img', { className: 'cinecrew-player__audio-poster', src: poster, alt: '' })
|
|
416
|
+
: h('div', { className: 'cinecrew-player__audio-placeholder', role: 'img', 'aria-label': 'Audio artwork placeholder' },
|
|
417
|
+
h(Icon, { name: 'audioOnly', icons, color: theme.accentColor })),
|
|
366
418
|
h('span', { className: 'cinecrew-player__audio-wave', style: { color: theme.accentColor }, 'aria-hidden': true }, '•••••••'),
|
|
367
419
|
h('strong', null, title || 'Audio only'),
|
|
368
420
|
h('button', {
|
|
@@ -478,7 +530,7 @@ function WebPlayerLayout(props) {
|
|
|
478
530
|
}
|
|
479
531
|
let audioCard = null;
|
|
480
532
|
if (props.audioOnly) {
|
|
481
|
-
audioCard = h(WebAudioOnlyCard, { poster: props.poster, title: props.title, theme: props.theme, onSwitchToVideo: props.onSwitchToVideo });
|
|
533
|
+
audioCard = h(WebAudioOnlyCard, { poster: props.poster, title: props.title, theme: props.theme, icons: props.icons, onSwitchToVideo: props.onSwitchToVideo });
|
|
482
534
|
}
|
|
483
535
|
let panelNode = null;
|
|
484
536
|
if (props.activePanel && props.webPanel) {
|
|
@@ -491,7 +543,7 @@ function WebPlayerLayout(props) {
|
|
|
491
543
|
return h('div', {
|
|
492
544
|
ref: props.playerRef,
|
|
493
545
|
className: `cinecrew-player${props.inlinePreview ? ' cinecrew-player--inline-preview' : ''}${props.drawerMode === 'resize' && props.activePanel ? ' cinecrew-player--drawer-resize' : ''} ${props.className}`.trim(),
|
|
494
|
-
style: { ...props.rootStyle, ...props.style, background: props.theme.backgroundColor, borderRadius: props.theme.borderRadius, '--cinecrew-accent': props.theme.accentColor, '--cinecrew-text': props.theme.controlColor, '--cinecrew-surface': props.theme.surfaceColor },
|
|
546
|
+
style: { ...props.rootStyle, ...props.style, background: props.theme.backgroundColor, borderRadius: props.theme.borderRadius, '--cinecrew-accent': props.theme.accentColor, '--cinecrew-text': props.theme.controlColor, '--cinecrew-surface': props.theme.surfaceColor, '--cinecrew-media-width': '64%' },
|
|
495
547
|
onWheel: props.onWheel,
|
|
496
548
|
'data-stream-mode': props.streamMode,
|
|
497
549
|
},
|
|
@@ -499,7 +551,7 @@ function WebPlayerLayout(props) {
|
|
|
499
551
|
h('div', { className: 'cinecrew-player__shade', style: { background: 'linear-gradient(180deg, rgba(0,0,0,.48), transparent 28%, transparent 68%, rgba(0,0,0,.64))' } }),
|
|
500
552
|
playerTitle,
|
|
501
553
|
loadingNotice,
|
|
502
|
-
h(WebPlayerError, { error: props.error, theme: props.theme, renderBackButton: props.renderBackButton }),
|
|
554
|
+
h(WebPlayerError, { error: props.error, theme: props.theme, renderBackButton: props.locked ? () => null : props.renderBackButton }),
|
|
503
555
|
controlLayer,
|
|
504
556
|
audioCard,
|
|
505
557
|
panelNode);
|
|
@@ -544,11 +596,11 @@ function getPanelRenderer(activePanel, renderLiveChat, renderEpg, integrations)
|
|
|
544
596
|
}
|
|
545
597
|
|
|
546
598
|
function createWebPanelNode({
|
|
547
|
-
renderer, integration, activePanel, integrations, source, title, theme, onClose,
|
|
599
|
+
renderer, integration, activePanel, integrations, source, title, theme, icons, onClose,
|
|
548
600
|
diagnostics, messagePageSize,
|
|
549
601
|
}) {
|
|
550
602
|
if (activePanel === 'diagnostics') {
|
|
551
|
-
return h(WebDiagnosticsPanel, { title, theme, ...diagnostics });
|
|
603
|
+
return h(WebDiagnosticsPanel, { title, theme, icons, onClose, ...diagnostics });
|
|
552
604
|
}
|
|
553
605
|
if (renderer) return h(renderer, { title, source, onClose });
|
|
554
606
|
if (!integration) return null;
|
|
@@ -568,26 +620,73 @@ function createWebPanelNode({
|
|
|
568
620
|
});
|
|
569
621
|
}
|
|
570
622
|
|
|
571
|
-
function
|
|
623
|
+
function getBufferedAhead(video, currentTime) {
|
|
624
|
+
if (!video?.buffered) return null;
|
|
625
|
+
for (let index = 0; index < video.buffered.length; index += 1) {
|
|
626
|
+
const start = video.buffered.start(index);
|
|
627
|
+
const end = video.buffered.end(index);
|
|
628
|
+
if (currentTime >= start && currentTime <= end) return Math.max(0, end - currentTime);
|
|
629
|
+
}
|
|
630
|
+
return 0;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
function getFrameQuality(video) {
|
|
634
|
+
try {
|
|
635
|
+
const quality = video?.getVideoPlaybackQuality?.();
|
|
636
|
+
if (quality) return { dropped: quality.droppedVideoFrames, total: quality.totalVideoFrames };
|
|
637
|
+
} catch {
|
|
638
|
+
// Playback quality is optional and may not be exposed by a media engine.
|
|
639
|
+
}
|
|
640
|
+
if (Number.isFinite(video?.webkitDroppedFrameCount) || Number.isFinite(video?.webkitDecodedFrameCount)) {
|
|
641
|
+
return { dropped: video.webkitDroppedFrameCount, total: video.webkitDecodedFrameCount };
|
|
642
|
+
}
|
|
643
|
+
return null;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
function WebDiagnosticsPanel({ title, theme, icons, onClose, streamMode, status, currentTime, duration, videoRef }) {
|
|
572
647
|
const video = videoRef?.current;
|
|
573
648
|
const resolution = video?.videoWidth && video?.videoHeight
|
|
574
649
|
? `${video.videoWidth} × ${video.videoHeight}`
|
|
575
650
|
: 'Not available';
|
|
576
|
-
const
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
651
|
+
const connection = globalThis.navigator?.connection;
|
|
652
|
+
const buffered = getBufferedAhead(video, currentTime);
|
|
653
|
+
const frames = getFrameQuality(video);
|
|
654
|
+
const cards = [
|
|
655
|
+
{ icon: 'display', label: 'Video resolution', value: resolution },
|
|
656
|
+
{ icon: 'network', label: 'Connection rate', value: Number.isFinite(connection?.downlink) ? `${connection.downlink} Mbps` : 'Not reported' },
|
|
657
|
+
{ icon: 'clock', label: 'Network RTT estimate', value: Number.isFinite(connection?.rtt) ? `${connection.rtt} ms` : 'Not reported' },
|
|
658
|
+
{ icon: 'buffer', label: 'Buffered ahead', value: buffered === null ? 'Not reported' : `${buffered.toFixed(1)} sec` },
|
|
659
|
+
{ icon: 'frames', label: 'Dropped / total frames', value: frames && Number.isFinite(frames.dropped) ? `${frames.dropped} / ${frames.total ?? '—'}` : 'Not reported' },
|
|
660
|
+
{ icon: 'speedometer', label: 'Playback position', value: `${formatTime(currentTime)} / ${formatTime(duration)}` },
|
|
661
|
+
{ icon: 'network', label: 'Connection type', value: connection?.effectiveType || 'Not reported' },
|
|
662
|
+
{ icon: 'video', label: 'Stream format', value: streamMode || 'Unknown' },
|
|
582
663
|
];
|
|
583
664
|
return h('section', {
|
|
584
665
|
className: 'cinecrew-player__diagnostics',
|
|
585
666
|
style: { color: theme.controlColor },
|
|
586
667
|
'aria-label': 'Stream diagnostics',
|
|
587
668
|
},
|
|
588
|
-
h('
|
|
589
|
-
|
|
590
|
-
|
|
669
|
+
h('header', { className: 'cinecrew-player__diagnostics-heading' },
|
|
670
|
+
h('div', null,
|
|
671
|
+
h('strong', null, 'Stream diagnostics'),
|
|
672
|
+
h('span', null, title || 'Current playback')),
|
|
673
|
+
h('button', {
|
|
674
|
+
type: 'button',
|
|
675
|
+
className: 'cinecrew-player__diagnostics-close',
|
|
676
|
+
onClick: onClose,
|
|
677
|
+
'aria-label': 'Close stream diagnostics',
|
|
678
|
+
title: 'Close diagnostics',
|
|
679
|
+
}, h(Icon, { name: 'close', icons, color: theme.controlColor }))),
|
|
680
|
+
h('div', { className: 'cinecrew-player__diagnostics-status' },
|
|
681
|
+
h('span', { className: `cinecrew-player__status-dot is-${String(status || 'unknown').toLowerCase()}` }),
|
|
682
|
+
h('span', null, status || 'Unknown'),
|
|
683
|
+
h('span', null, streamMode || 'Unknown format')),
|
|
684
|
+
h('div', { className: 'cinecrew-player__diagnostic-grid' },
|
|
685
|
+
cards.map(({ icon, label, value }) => h('article', { className: 'cinecrew-player__diagnostic-card', key: label },
|
|
686
|
+
h('span', { className: 'cinecrew-player__diagnostic-icon' }, h(Icon, { name: icon, icons, color: theme.accentColor })),
|
|
687
|
+
h('span', { className: 'cinecrew-player__diagnostic-label' }, label),
|
|
688
|
+
h('strong', null, value)))),
|
|
689
|
+
h('small', { className: 'cinecrew-player__diagnostics-note' }, 'Network rate and RTT are browser-reported estimates when supported; no extra ping or stream requests are sent.'));
|
|
591
690
|
}
|
|
592
691
|
|
|
593
692
|
function getChatMessageKey(message, index = 0) {
|
|
@@ -704,7 +803,12 @@ function WebChatComposer({ sending, canSend, onSend }) {
|
|
|
704
803
|
'aria-label': 'Chat message',
|
|
705
804
|
maxLength: 1000,
|
|
706
805
|
}),
|
|
707
|
-
h('button', {
|
|
806
|
+
h('button', {
|
|
807
|
+
type: 'submit',
|
|
808
|
+
disabled: sending || !message.trim() || !canSend,
|
|
809
|
+
'aria-label': sending ? 'Sending message' : 'Send message',
|
|
810
|
+
title: sending ? 'Sending…' : 'Send message',
|
|
811
|
+
}, h(Icon, { name: 'send', color: '#07111e' }))),
|
|
708
812
|
emojiOpen ? h(WebEmojiPicker, { onSelect: insertEmoji }) : null);
|
|
709
813
|
}
|
|
710
814
|
|
|
@@ -1252,6 +1356,7 @@ export const CineCrewPlayer = forwardRef(function CineCrewPlayer(props, ref) {
|
|
|
1252
1356
|
source: panelSource,
|
|
1253
1357
|
title,
|
|
1254
1358
|
theme,
|
|
1359
|
+
icons,
|
|
1255
1360
|
onClose: () => setActivePanel(null),
|
|
1256
1361
|
diagnostics: {
|
|
1257
1362
|
streamMode,
|
package/src/web/styles.css
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
|
|
31
31
|
.cinecrew-player__video,
|
|
32
32
|
.cinecrew-player__youtube {
|
|
33
|
-
transition: width 180ms ease, height 180ms ease, top 180ms ease;
|
|
33
|
+
transition: width 180ms ease, height 180ms ease, top 180ms ease, left 180ms ease, transform 180ms ease;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
.cinecrew-player__shade {
|
|
@@ -131,15 +131,22 @@
|
|
|
131
131
|
.cinecrew-player__seek {
|
|
132
132
|
flex: 0 0 auto;
|
|
133
133
|
width: 100%;
|
|
134
|
+
align-items: center;
|
|
134
135
|
font-variant-numeric: tabular-nums;
|
|
135
136
|
text-shadow: 0 1px 3px #000;
|
|
136
137
|
}
|
|
137
138
|
|
|
139
|
+
.cinecrew-player__seek > span {
|
|
140
|
+
min-width: 3.4em;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.cinecrew-player__seek > span:last-child { text-align: right; }
|
|
144
|
+
|
|
138
145
|
.cinecrew-player__seek input {
|
|
139
146
|
flex: 1;
|
|
140
147
|
min-width: 50px;
|
|
141
148
|
min-height: 24px;
|
|
142
|
-
touch-action:
|
|
149
|
+
touch-action: pan-y;
|
|
143
150
|
cursor: ew-resize;
|
|
144
151
|
}
|
|
145
152
|
|
|
@@ -193,8 +200,9 @@
|
|
|
193
200
|
|
|
194
201
|
.cinecrew-player__audio-card {
|
|
195
202
|
position: absolute;
|
|
196
|
-
inset:
|
|
203
|
+
inset: 0;
|
|
197
204
|
z-index: 5;
|
|
205
|
+
box-sizing: border-box;
|
|
198
206
|
display: flex;
|
|
199
207
|
flex-direction: column;
|
|
200
208
|
align-items: center;
|
|
@@ -202,7 +210,7 @@
|
|
|
202
210
|
gap: 18px;
|
|
203
211
|
padding: 24px;
|
|
204
212
|
border: 1px solid;
|
|
205
|
-
border-radius:
|
|
213
|
+
border-radius: inherit;
|
|
206
214
|
text-align: center;
|
|
207
215
|
box-shadow: 0 18px 60px rgba(0, 0, 0, .32);
|
|
208
216
|
}
|
|
@@ -214,6 +222,23 @@
|
|
|
214
222
|
border-radius: 50%;
|
|
215
223
|
}
|
|
216
224
|
|
|
225
|
+
.cinecrew-player__audio-placeholder {
|
|
226
|
+
display: grid;
|
|
227
|
+
width: min(30vw, 160px);
|
|
228
|
+
aspect-ratio: 1;
|
|
229
|
+
place-items: center;
|
|
230
|
+
border: 2px solid var(--cinecrew-accent, #00d4ff);
|
|
231
|
+
border-radius: 50%;
|
|
232
|
+
background: radial-gradient(circle at 35% 30%, rgba(0, 212, 255, .28), transparent 58%), linear-gradient(145deg, #142b49, #081321 72%);
|
|
233
|
+
box-shadow: 0 0 28px rgba(0, 212, 255, .2), inset 0 0 22px rgba(0, 212, 255, .12);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
.cinecrew-player__audio-placeholder .cinecrew-player__icon {
|
|
237
|
+
width: 42px;
|
|
238
|
+
height: 42px;
|
|
239
|
+
font-size: 42px;
|
|
240
|
+
}
|
|
241
|
+
|
|
217
242
|
.cinecrew-player__audio-wave {
|
|
218
243
|
letter-spacing: .28em;
|
|
219
244
|
font-size: 1.25rem;
|
|
@@ -302,36 +327,120 @@
|
|
|
302
327
|
font: inherit;
|
|
303
328
|
}
|
|
304
329
|
|
|
330
|
+
.cinecrew-player__menu-empty {
|
|
331
|
+
padding: 10px 13px;
|
|
332
|
+
color: var(--cinecrew-text, #fff);
|
|
333
|
+
white-space: nowrap;
|
|
334
|
+
}
|
|
335
|
+
|
|
305
336
|
.cinecrew-player__menu-wrap--aspect .cinecrew-player__menu button {
|
|
306
337
|
padding-block: 6px;
|
|
307
338
|
}
|
|
308
339
|
|
|
309
340
|
.cinecrew-player__diagnostics {
|
|
310
341
|
display: flex;
|
|
342
|
+
box-sizing: border-box;
|
|
343
|
+
height: 100%;
|
|
311
344
|
flex-direction: column;
|
|
312
|
-
gap:
|
|
313
|
-
min-width:
|
|
345
|
+
gap: 14px;
|
|
346
|
+
min-width: 0;
|
|
347
|
+
overflow: auto;
|
|
314
348
|
}
|
|
315
349
|
|
|
316
|
-
.cinecrew-player__diagnostics
|
|
317
|
-
|
|
350
|
+
.cinecrew-player__diagnostics-heading {
|
|
351
|
+
display: flex;
|
|
352
|
+
align-items: flex-start;
|
|
353
|
+
justify-content: space-between;
|
|
354
|
+
gap: 12px;
|
|
355
|
+
padding-bottom: 12px;
|
|
318
356
|
border-bottom: 1px solid rgba(255, 255, 255, .14);
|
|
319
357
|
}
|
|
320
358
|
|
|
321
|
-
.cinecrew-
|
|
359
|
+
.cinecrew-player__diagnostics-heading > div {
|
|
322
360
|
display: flex;
|
|
323
|
-
|
|
324
|
-
|
|
361
|
+
min-width: 0;
|
|
362
|
+
flex-direction: column;
|
|
363
|
+
gap: 3px;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
.cinecrew-player__diagnostics-heading strong { font-size: 1.05rem; }
|
|
367
|
+
.cinecrew-player__diagnostics-heading > div > span { opacity: .7; overflow-wrap: anywhere; }
|
|
368
|
+
|
|
369
|
+
.cinecrew-player__diagnostics-close {
|
|
370
|
+
display: grid;
|
|
371
|
+
flex: 0 0 36px;
|
|
372
|
+
width: 36px;
|
|
373
|
+
height: 36px;
|
|
374
|
+
place-items: center;
|
|
375
|
+
border: 1px solid rgba(255,255,255,.2);
|
|
376
|
+
border-radius: 50%;
|
|
377
|
+
color: inherit;
|
|
378
|
+
background: rgba(255,255,255,.1);
|
|
379
|
+
cursor: pointer;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
.cinecrew-player__diagnostics-status {
|
|
383
|
+
display: flex;
|
|
384
|
+
align-items: center;
|
|
385
|
+
gap: 8px;
|
|
386
|
+
align-self: flex-start;
|
|
387
|
+
padding: 6px 10px;
|
|
388
|
+
border: 1px solid rgba(255,255,255,.15);
|
|
389
|
+
border-radius: 999px;
|
|
390
|
+
background: rgba(255,255,255,.07);
|
|
391
|
+
font-size: .86em;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
.cinecrew-player__status-dot {
|
|
395
|
+
width: 8px;
|
|
396
|
+
height: 8px;
|
|
397
|
+
border-radius: 50%;
|
|
398
|
+
background: #9ba9bb;
|
|
399
|
+
box-shadow: 0 0 10px currentColor;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
.cinecrew-player__status-dot.is-playing { color: #42d392; background: currentColor; }
|
|
403
|
+
.cinecrew-player__status-dot.is-buffering { color: #ffca58; background: currentColor; }
|
|
404
|
+
.cinecrew-player__status-dot.is-error { color: #ff647c; background: currentColor; }
|
|
405
|
+
|
|
406
|
+
.cinecrew-player__diagnostic-grid {
|
|
407
|
+
display: grid;
|
|
408
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
409
|
+
gap: 9px;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
.cinecrew-player__diagnostic-card {
|
|
413
|
+
display: grid;
|
|
414
|
+
min-width: 0;
|
|
415
|
+
grid-template-columns: 32px minmax(0, 1fr);
|
|
416
|
+
grid-template-rows: auto auto;
|
|
417
|
+
align-items: center;
|
|
418
|
+
column-gap: 9px;
|
|
419
|
+
row-gap: 3px;
|
|
420
|
+
padding: 10px;
|
|
421
|
+
border: 1px solid rgba(255,255,255,.14);
|
|
422
|
+
border-radius: 12px;
|
|
423
|
+
background: rgba(255,255,255,.08);
|
|
325
424
|
font-variant-numeric: tabular-nums;
|
|
326
425
|
}
|
|
327
426
|
|
|
328
|
-
.cinecrew-player__diagnostic-
|
|
329
|
-
|
|
427
|
+
.cinecrew-player__diagnostic-icon {
|
|
428
|
+
display: grid;
|
|
429
|
+
width: 30px;
|
|
430
|
+
height: 30px;
|
|
431
|
+
grid-row: span 2;
|
|
432
|
+
place-items: center;
|
|
433
|
+
border-radius: 9px;
|
|
434
|
+
background: rgba(255,255,255,.08);
|
|
330
435
|
}
|
|
331
436
|
|
|
332
|
-
.cinecrew-player__diagnostic-
|
|
333
|
-
|
|
334
|
-
|
|
437
|
+
.cinecrew-player__diagnostic-icon .cinecrew-player__icon { width: 18px; height: 18px; }
|
|
438
|
+
.cinecrew-player__diagnostic-label { overflow: hidden; opacity: .7; font-size: .76em; text-overflow: ellipsis; white-space: nowrap; }
|
|
439
|
+
.cinecrew-player__diagnostic-card strong { overflow-wrap: anywhere; font-size: .9em; }
|
|
440
|
+
.cinecrew-player__diagnostics-note { opacity: .65; line-height: 1.35; }
|
|
441
|
+
|
|
442
|
+
@media (max-width: 420px) {
|
|
443
|
+
.cinecrew-player__diagnostic-grid { grid-template-columns: minmax(0, 1fr); }
|
|
335
444
|
}
|
|
336
445
|
|
|
337
446
|
.cinecrew-player__panel-content {
|
|
@@ -420,17 +529,18 @@
|
|
|
420
529
|
position: relative;
|
|
421
530
|
display: flex;
|
|
422
531
|
align-items: center;
|
|
423
|
-
gap:
|
|
424
|
-
padding: 6px;
|
|
425
|
-
border: 1px solid rgba(255, 255, 255, .
|
|
426
|
-
border-radius:
|
|
427
|
-
background: rgba(
|
|
532
|
+
gap: 7px;
|
|
533
|
+
padding: 5px 6px 5px 10px;
|
|
534
|
+
border: 1px solid rgba(255, 255, 255, .22);
|
|
535
|
+
border-radius: 14px;
|
|
536
|
+
background: rgba(12, 20, 32, .72);
|
|
537
|
+
box-shadow: 0 3px 12px rgba(0,0,0,.12);
|
|
428
538
|
transition: border-color .16s ease, box-shadow .16s ease, background-color .16s ease;
|
|
429
539
|
}
|
|
430
540
|
|
|
431
541
|
.cinecrew-player__chat-composer:focus-within {
|
|
432
542
|
border-color: var(--cinecrew-accent);
|
|
433
|
-
background: rgba(
|
|
543
|
+
background: rgba(12, 20, 32, .88);
|
|
434
544
|
box-shadow: 0 0 0 3px color-mix(in srgb, var(--cinecrew-accent) 18%, transparent);
|
|
435
545
|
}
|
|
436
546
|
|
|
@@ -439,7 +549,7 @@
|
|
|
439
549
|
min-width: 0;
|
|
440
550
|
border: 0;
|
|
441
551
|
outline: 0;
|
|
442
|
-
padding:
|
|
552
|
+
padding: 10px 4px;
|
|
443
553
|
color: inherit;
|
|
444
554
|
background: transparent;
|
|
445
555
|
font: inherit;
|
|
@@ -468,15 +578,19 @@
|
|
|
468
578
|
}
|
|
469
579
|
|
|
470
580
|
.cinecrew-player__chat-composer button[type="submit"] {
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
581
|
+
width: 40px;
|
|
582
|
+
min-width: 40px;
|
|
583
|
+
height: 40px;
|
|
584
|
+
min-height: 40px;
|
|
585
|
+
padding: 0;
|
|
586
|
+
border-radius: 12px;
|
|
474
587
|
color: #07111e;
|
|
475
588
|
background: var(--cinecrew-accent);
|
|
476
|
-
font-weight: 700;
|
|
477
589
|
box-shadow: 0 2px 8px color-mix(in srgb, var(--cinecrew-accent) 24%, transparent);
|
|
478
590
|
}
|
|
479
591
|
|
|
592
|
+
.cinecrew-player__chat-composer button[type="submit"] .cinecrew-player__icon { width: 19px; height: 19px; }
|
|
593
|
+
|
|
480
594
|
.cinecrew-player__chat-composer button[type="submit"]:hover:not(:disabled) {
|
|
481
595
|
filter: brightness(1.08);
|
|
482
596
|
}
|
|
@@ -649,15 +763,31 @@
|
|
|
649
763
|
padding: 16px;
|
|
650
764
|
border-left: 1px solid rgba(255,255,255,.2);
|
|
651
765
|
border-radius: 0;
|
|
652
|
-
background: rgba(13, 26, 44, .
|
|
653
|
-
backdrop-filter: blur(
|
|
766
|
+
background: rgba(13, 26, 44, .58);
|
|
767
|
+
backdrop-filter: blur(10px);
|
|
654
768
|
box-shadow: -12px 0 34px rgba(0,0,0,.34);
|
|
655
769
|
animation: cinecrew-drawer-in 180ms ease-out both;
|
|
656
770
|
}
|
|
657
771
|
|
|
658
|
-
.cinecrew-player--drawer-resize .cinecrew-player__panel {
|
|
772
|
+
.cinecrew-player--drawer-resize .cinecrew-player__panel {
|
|
773
|
+
width: calc(100% - var(--cinecrew-media-width, 64%));
|
|
774
|
+
max-width: none;
|
|
775
|
+
padding: 14px;
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
.cinecrew-player__panel.is-resizing { background: rgba(13, 26, 44, .82); }
|
|
659
779
|
|
|
660
|
-
.cinecrew-
|
|
780
|
+
.cinecrew-player--drawer-resize .cinecrew-player__shade,
|
|
781
|
+
.cinecrew-player--drawer-resize .cinecrew-player__controls,
|
|
782
|
+
.cinecrew-player--drawer-resize .cinecrew-player__status,
|
|
783
|
+
.cinecrew-player--drawer-resize .cinecrew-player__error {
|
|
784
|
+
right: auto;
|
|
785
|
+
width: var(--cinecrew-media-width, 64%);
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
.cinecrew-player--drawer-resize .cinecrew-player__title {
|
|
789
|
+
right: calc(100% - var(--cinecrew-media-width, 64%));
|
|
790
|
+
}
|
|
661
791
|
|
|
662
792
|
.cinecrew-player__panel-close {
|
|
663
793
|
position: absolute;
|
|
@@ -699,4 +829,6 @@
|
|
|
699
829
|
.cinecrew-player__bottom-actions { align-items: flex-end; gap: 6px; }
|
|
700
830
|
.cinecrew-player__bottom-right-actions { max-width: 100%; flex-wrap: wrap; justify-content: flex-end; gap: 4px; }
|
|
701
831
|
.cinecrew-player__panel { width: min(380px, 92%); }
|
|
832
|
+
.cinecrew-player--drawer-resize { --cinecrew-media-width: 52% !important; }
|
|
833
|
+
.cinecrew-player--drawer-resize .cinecrew-player__panel { width: calc(100% - var(--cinecrew-media-width)); padding: 10px; }
|
|
702
834
|
}
|