saltfish 0.2.65 → 0.2.66
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/dist/managers/CursorManager.d.ts +5 -0
- package/dist/managers/CursorManager.d.ts.map +1 -1
- package/dist/managers/ShadowDOMManager.d.ts.map +1 -1
- package/dist/managers/UIManager.d.ts.map +1 -1
- package/dist/managers/VideoManager.d.ts.map +1 -1
- package/dist/player.js +2 -2
- package/dist/player.min.js +2 -2
- package/dist/saltfish-playlist-player.es.js +199 -137
- package/dist/saltfish-playlist-player.umd.js +1 -1
- package/dist/styles/index.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -3719,26 +3719,28 @@ __publicField(_ManagerOrchestrator, "prevState", {
|
|
|
3719
3719
|
isMinimized: false
|
|
3720
3720
|
});
|
|
3721
3721
|
let ManagerOrchestrator = _ManagerOrchestrator;
|
|
3722
|
-
const baseResetCss = "/* \n * CSS Reset for the Saltfish playlist Player\n * Minimal reset for the Shadow DOM to ensure consistent rendering\n */\n\n:host {\n all: initial;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;\n box-sizing: border-box;\n}\n\n:host *,\n:host *::before,\n:host *::after {\n box-sizing: inherit;\n margin: 0;\n padding: 0;\n}\n\nbutton {\n background: none;\n border: none;\n cursor: pointer;\n font: inherit;\n outline: none;\n padding: 0;\n} ";
|
|
3722
|
+
const baseResetCss = "/* \n * CSS Reset for the Saltfish playlist Player\n * Minimal reset for the Shadow DOM to ensure consistent rendering\n */\n\n:host {\n all: initial;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;\n box-sizing: border-box;\n}\n\n:host *,\n:host *::before,\n:host *::after {\n box-sizing: inherit;\n margin: 0;\n padding: 0;\n}\n\nbutton {\n background: none;\n border: none;\n cursor: pointer;\n font: inherit;\n outline: none;\n padding: 0;\n}\n\n/* Utility classes for CSP-compliant styling */\n.sf-hidden {\n display: none !important;\n} ";
|
|
3723
3723
|
const baseVariablesCss = "/* \n * Variables for the Saltfish playlist Player\n * Defines all design tokens used throughout the application\n */\n\n:host {\n /* Colors */\n --sf-primary-color: #4a9bff;\n --sf-secondary-color: #6ccfff;\n --sf-background-color: #1e1e1e;\n --sf-text-color: #ffffff;\n --sf-button-bg: rgba(0, 0, 0, 0.5);\n --sf-button-hover-bg: rgba(0, 0, 0, 0.7);\n --sf-overlay-gradient: linear-gradient(180deg, rgba(0, 0, 0, 0.7) 0%, transparent 30%, transparent 70%, rgba(0, 0, 0, 0.7) 100%);\n --sf-progress-gradient: linear-gradient(90deg, var(--sf-primary-color), var(--sf-secondary-color));\n --sf-error-color: #ff4d4d;\n --sf-error-bg: rgba(255, 77, 77, 0.1);\n \n /* Spacing */\n --sf-spacing-xs: 4px;\n --sf-spacing-sm: 8px;\n --sf-spacing-md: 12px;\n --sf-spacing-lg: 16px;\n --sf-spacing-xl: 24px;\n \n /* Sizes */\n --sf-player-width: 240px;\n --sf-player-height: 336px;\n --sf-player-min-width: 80px;\n --sf-player-min-height: 80px;\n --sf-control-button-size: 24px;\n --sf-play-button-size: 60px;\n --sf-minimize-button-size: 34px;\n --sf-mute-button-size: 32px;\n --sf-cc-button-size: 32px;\n --sf-cursor-size: 32px;\n \n /* Border radius */\n --sf-border-radius-sm: 4px;\n --sf-border-radius-md: 8px;\n --sf-border-radius-lg: 16px;\n --sf-border-radius-circle: 50%;\n \n /* Transitions */\n --sf-transition-fast: 0.1s ease;\n --sf-transition-normal: 0.2s ease;\n --sf-transition-slow: 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);\n \n /* Shadows */\n --sf-shadow-small: 0 2px 5px rgba(0, 0, 0, 0.2);\n --sf-shadow-medium: 0 4px 8px rgba(0, 0, 0, 0.15);\n --sf-shadow-large: 0 10px 25px rgba(0, 0, 0, 0.2);\n \n /* Z-index layering */\n --sf-z-index-base: 1;\n --sf-z-index-overlay: 2;\n --sf-z-index-controls: 10;\n --sf-z-index-cursor: 9999;\n --sf-z-index-player: 2147483648;\n \n /* Font sizes */\n --sf-font-size-sm: 14px;\n --sf-font-size-md: 16px;\n --sf-font-size-lg: 18px;\n --sf-font-size-xl: 24px;\n} \n\n/* Mobile device responsive adjustments - make player smaller for mobile screens */\n@media (max-width: 768px) {\n :host {\n /* Reduce player size on mobile for better space utilization */\n --sf-player-width: 180px; /* 25% smaller than desktop (240px -> 180px) */\n --sf-player-height: 252px; /* 25% smaller than desktop (336px -> 252px) */\n --sf-player-min-width: 60px; /* Smaller when minimized (80px -> 60px) */\n --sf-player-min-height: 60px; /* Smaller when minimized (80px -> 60px) */\n \n /* Keep controls touch-friendly despite smaller player size */\n --sf-play-button-size: 44px; /* Smaller but still touch-friendly (60px -> 44px) */\n --sf-control-button-size: 28px; /* Keep larger for touch targets (24px -> 28px) */\n --sf-mute-button-size: 26px; /* Smaller for mobile (32px -> 26px) */\n --sf-cc-button-size: 26px; /* Smaller for mobile (32px -> 26px) */\n --sf-minimize-button-size: 26px; /* Match other mobile button sizes */\n }\n}\n\n/* Touch device specific adjustments (tablets and larger touch devices, excluding mobile) */\n@media (pointer: coarse) and (min-width: 769px) {\n :host {\n /* Ensure touch-friendly sizes even on larger touch devices */\n --sf-control-button-size: 28px;\n --sf-mute-button-size: 38px;\n --sf-cc-button-size: 38px;\n --sf-minimize-button-size: 38px; /* Match other touch device button sizes */\n }\n} ";
|
|
3724
|
-
const componentsPlayerCss = "/* \n * Player component styles for the Saltfish playlist Player\n * Following BEM naming convention\n */\n\n/* Main player container */\n.sf-player {\n border-radius: var(--sf-border-radius-lg);\n box-shadow: 0 25px 50px rgba(0, 0, 0, 0.45), 0 10px 20px rgba(0, 0, 0, 0.3), 0 0 0 2px rgba(255, 255, 255, 0.08);\n transition: all var(--sf-transition-slow);\n position: relative;\n backdrop-filter: blur(10px);\n -webkit-backdrop-filter: blur(10px);\n opacity: 0;\n transition: opacity 0.3s ease-in-out;\n}\n\n/* Player visible state - show with fade in */\n.sf-player--visible {\n opacity: 1;\n}\n\n/* Dark gradient overlay at bottom of player */\n.sf-player::before {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 33.33%; /* One third of player height */\n background: linear-gradient(to top, rgba(0, 0, 0, 0.8) 0%, rgba(0, 0, 0, 0) 100%);\n pointer-events: none;\n z-index: var(--sf-z-index-overlay);\n border-radius: 8px;\n}\n\n/* Hide gradient overlay when minimized */\n.sf-player--minimized::before {\n display: none;\n}\n\n/* Full-size player state */\n.sf-player:not(.sf-player--minimized) {\n width: var(--sf-player-width);\n height: var(--sf-player-height);\n}\n\n/* Autoplay fallback state - ensure play button is visible */\n.sf-player--waiting-for-user-interaction .sf-controls-container__play-button {\n display: flex !important;\n opacity: 1 !important;\n visibility: visible !important;\n}\n\n/* Also show the center play button in autoplay fallback state */\n.sf-player--waiting-for-user-interaction .sf-player__center-play-button {\n display: flex !important;\n opacity: 1 !important;\n z-index: calc(var(--sf-z-index-controls) + 20) !important; /* Higher z-index to appear above overlay */\n}\n\n/* Make the autoplay fallback state more prominent to indicate need for interaction */\n.sf-player--waiting-for-user-interaction::after {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n pointer-events: none;\n z-index: var(--sf-z-index-overlay);\n}\n\n/* Player state: minimized */\n.sf-player--minimized {\n /* Equal width and height are essential for maintaining a perfect circle when using border-radius: 50% */\n width: var(--sf-player-min-width);\n height: var(--sf-player-min-height);\n border-radius: var(--sf-border-radius-circle);\n box-shadow: 0 15px 30px rgba(0, 0, 0, 0.35), 0 5px 15px rgba(0, 0, 0, 0.25), 0 0 0 2px rgba(255, 255, 255, 0.08);\n cursor: pointer;\n /* Force overriding any inline styles that might be applied */\n max-width: var(--sf-player-min-width) !important;\n max-height: var(--sf-player-min-height) !important;\n min-width: var(--sf-player-min-width) !important;\n min-height: var(--sf-player-min-height) !important;\n}\n\n/* Hide controls when minimized */\n.sf-player--minimized .sf-controls-container {\n display: none;\n}\n\n/* Only show the minimize button when hovering on minimized player */\n.sf-player--minimized .sf-player__minimize-button {\n opacity: 0;\n}\n\n.sf-player--minimized:hover .sf-player__minimize-button {\n opacity: 1;\n}\n\n/* Player root element */\n#sf-player-root {\n position: fixed;\n z-index: var(--sf-z-index-player);\n}\n\n/* Fixed positioning classes */\n.sf-player-root--bottom-left {\n bottom: 20px;\n left: 20px;\n}\n\n.sf-player-root--bottom-right {\n bottom: 20px;\n right: 20px;\n}\n\n/* Player error message */\n.sf-player__error {\n padding: var(--sf-spacing-md);\n color: var(--sf-error-color);\n background-color: var(--sf-error-bg);\n border-radius: var(--sf-border-radius-md);\n margin: var(--sf-spacing-sm);\n font-size: var(--sf-font-size-sm);\n border-left: 4px solid var(--sf-error-color);\n}\n\n/* Minimize button */\n.sf-player__minimize-button {\n position: absolute;\n top: 8px;\n right: 6px;\n width: var(--sf-minimize-button-size);\n height: var(--sf-minimize-button-size);\n background-color: transparent;\n border-radius: var(--sf-border-radius-circle);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n z-index: var(--sf-z-index-controls);\n color: white;\n border: none;\n font-size: calc(var(--sf-font-size-sm) + 4px);\n transition: all var(--sf-transition-normal);\n text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\n opacity: 0;\n}\n\n/* Minimize button hover state */\n.sf-player__minimize-button:hover {\n transform: scale(1.1);\n}\n\n/* Show minimize button on player hover */\n.sf-player:hover .sf-player__minimize-button {\n opacity: 1;\n}\n\n/* Mobile and touch device overrides for minimize button visibility */\n/* Ensure minimize button is always visible on touch devices, even when minimized */\n@media (pointer: coarse) {\n .sf-player__minimize-button {\n opacity: 1 !important;\n z-index: calc(var(--sf-z-index-controls) + 50) !important; /* Much higher z-index for touch devices */\n }\n \n .sf-player--minimized .sf-player__minimize-button {\n opacity: 1 !important;\n z-index: calc(var(--sf-z-index-controls) + 50) !important; /* Much higher z-index for touch devices */\n }\n}\n\n/* Ensure minimize button is always visible on mobile screens under 768px */\n@media (max-width: 768px) {\n .sf-player__minimize-button {\n opacity: 1 !important;\n z-index: calc(var(--sf-z-index-controls) + 50) !important; /* Much higher z-index for mobile */\n /* Position closer to top right corner on mobile */\n top: var(--sf-spacing-xs) !important; /* 4px from top instead of 16px */\n right: var(--sf-spacing-xs) !important; /* 4px from right instead of 12px */\n }\n \n .sf-player--minimized .sf-player__minimize-button {\n opacity: 1 !important;\n z-index: calc(var(--sf-z-index-controls) + 50) !important; /* Much higher z-index for mobile */\n /* Position closer to top right corner on mobile */\n top: var(--sf-spacing-xs) !important; /* 4px from top instead of 16px */\n right: var(--sf-spacing-xs) !important; /* 4px from right instead of 12px */\n }\n}\n\n/* Player title */\n.sf-player__title {\n position: absolute;\n top: var(--sf-spacing-md);\n left: var(--sf-spacing-md);\n color: var(--sf-text-color);\n font-size: var(--sf-font-size-md);\n font-weight: 600;\n z-index: var(--sf-z-index-controls);\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);\n max-width: 70%;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n/* Centered play/pause button overlay */\n.sf-player__center-play-button {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: var(--sf-play-button-size);\n height: var(--sf-play-button-size);\n background-color: rgba(0, 0, 0, 0.5);\n border-radius: var(--sf-border-radius-circle);\n display: none; /* Hidden by default */\n justify-content: center;\n align-items: center;\n z-index: calc(var(--sf-z-index-controls) + 10); /* Ensure higher z-index than other elements */\n color: white;\n border: none;\n font-size: var(--sf-control-button-size);\n cursor: pointer;\n transition: transform var(--sf-transition-normal), background-color var(--sf-transition-normal);\n backdrop-filter: blur(3px);\n -webkit-backdrop-filter: blur(3px);\n box-shadow: 0 15px 30px rgba(0, 0, 0, 0.5), 0 5px 15px rgba(0, 0, 0, 0.3), 0 0 0 2px rgba(255, 255, 255, 0.08);\n pointer-events: auto; /* Enable pointer events to capture clicks */\n}\n\n/* Center play button hover state */\n.sf-player__center-play-button:hover {\n transform: translate(-50%, -50%) scale(1.1);\n background-color: rgba(0, 0, 0, 0.7);\n}\n\n/* Hide center play button in minimized state */\n.sf-player--minimized .sf-player__center-play-button {\n display: none !important;\n}\n\n/* Center play button with adjustment for 3+ buttons */\n.sf-player__center-play-button--with-many-buttons {\n transform: translate(-50%, -85%) !important; /* Move up by adjusting Y offset */\n}\n\n/* Exit button for minimized mode */\n.sf-player__exit-button {\n position: absolute;\n top: -22px; /* Position it above the player */\n right: 0;\n width: 20px;\n height: 20px;\n background-color: var(--sf-button-bg);\n border-radius: var(--sf-border-radius-circle);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n z-index: var(--sf-z-index-controls);\n color: white;\n border: none;\n font-size: var(--sf-font-size-md);\n transition: all var(--sf-transition-normal);\n text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\n box-shadow: 0 5px 15px rgba(0, 0, 0, 0.35);\n}\n\n/* Exit button hover state */\n.sf-player__exit-button:hover {\n transform: scale(1.1);\n background-color: var(--sf-button-hover-bg);\n}\n\n/* Show exit button on minimized player hover */\n.sf-player--minimized:hover .sf-player__exit-button {\n opacity: 1;\n}\n\n/* Saltfish logo */\n.sf-player__logo {\n position: absolute;\n bottom: var(--sf-spacing-xs);\n left: 0;\n right: 0;\n height: 18px;\n z-index: var(--sf-z-index-controls);\n opacity: 0.7;\n transition: opacity var(--sf-transition-normal);\n cursor: pointer;\n display: flex;\n justify-content: center;\n align-items: center;\n}\n\n.sf-player__logo svg {\n width: 55px;\n height: 20px;\n}\n\n/* Logo hover state */\n.sf-player:hover .sf-player__logo {\n opacity: 0.9;\n}\n\n/* Hide logo when minimized */\n.sf-player--minimized .sf-player__logo {\n display: none;\n} ";
|
|
3725
|
-
const componentsVideoCss = "/* \n * Video component styles for the Saltfish playlist Player\n * Following BEM naming convention\n */\n\n/* Video container */\n.sf-video-container {\n position: relative;\n width: 100%;\n height: 100%;\n border-radius: var(--sf-border-radius-md);\n overflow: hidden;\n pointer-events: auto; /* Ensure clicks on video container are captured */\n background-color: #000; /* Fallback background for audio-only mode */\n}\n\n/* Audio fallback poster image */\n.sf-video-container--audio-fallback {\n background-size: cover;\n background-position: center;\n background-repeat: no-repeat;\n}\n\n/* Audio fallback overlay */\n.sf-audio-fallback-overlay {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n background: rgba(0, 0, 0, 0.6);\n z-index: 2;\n pointer-events: none;\n}\n\n.sf-audio-fallback-overlay__icon {\n width: 60px;\n height: 60px;\n margin-bottom: 16px;\n color: white;\n opacity: 0.9;\n}\n\n.sf-audio-fallback-overlay__text {\n color: white;\n font-size: 14px;\n text-align: center;\n padding: 0 20px;\n text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);\n opacity: 0.9;\n}\n\n/* Video element */\n.sf-video-container__video {\n width: 100%;\n height: 100%;\n object-fit: cover;\n /* Ensure video is visible on mobile */\n display: block;\n /* Add explicit positioning to ensure video is visible */\n position: relative;\n z-index: 1;\n}\n\n\n\n/* Mobile-specific video styles */\n@media (max-width: 768px) {\n \n .sf-video-container__video {\n /* Force video dimensions on mobile */\n width: 100% !important;\n height: 100% !important;\n object-fit: cover !important;\n /* Prevent video from being hidden */\n opacity: 1 !important;\n visibility: visible !important;\n /* Ensure video is above any potential overlays */\n z-index: 10 !important;\n position: relative !important;\n }\n \n /* Make controls more touch-friendly on mobile */\n .sf-video-container__controls {\n height: 5px; /* Thicker on mobile for easier touch */\n }\n \n .sf-video-container__mute-button {\n /* Use CSS variable for consistent sizing */\n min-width: var(--sf-mute-button-size) !important;\n min-height: var(--sf-mute-button-size) !important;\n opacity: 1; /* Always visible on mobile (no hover) */\n }\n \n .sf-video-container__cc-button {\n /* Use CSS variable for consistent sizing */\n min-width: var(--sf-cc-button-size) !important;\n min-height: var(--sf-cc-button-size) !important;\n opacity: 1; /* Always visible on mobile (no hover) */\n }\n}\n\n/* Touch device specific styles */\n@media (pointer: coarse) {\n .sf-video-container__controls:hover {\n height: 5px; /* Keep consistent height on touch devices */\n }\n \n .sf-video-container__mute-button {\n opacity: 1; /* Always show on touch devices */\n }\n \n .sf-video-container__cc-button {\n opacity: 1; /* Always show on touch devices */\n }\n \n .sf-video-container:hover .sf-video-container__mute-button {\n opacity: 1;\n }\n}\n\n/* Video in minimized state */\n.sf-player--minimized .sf-video-container {\n border-radius: var(--sf-border-radius-circle);\n cursor: pointer;\n z-index: var(--sf-z-index-base);\n width: 100%;\n height: 100%;\n}\n\n.sf-player--minimized .sf-video-container__video {\n border-radius: var(--sf-border-radius-circle);\n object-fit: cover;\n width: 100%;\n height: 100%;\n}\n\n/* Hide progress bar in minimized state */\n.sf-player--minimized .sf-video-container__controls {\n display: none !important;\n}\n\n/* Also hide mute button in minimized state */\n.sf-player--minimized .sf-video-container__mute-button {\n display: none !important;\n}\n\n/* Also hide CC button in minimized state */\n.sf-player--minimized .sf-video-container__cc-button {\n display: none !important;\n}\n\n/* Progress bar container */\n.sf-video-container__controls {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 3px;\n background-color: rgba(255, 255, 255, 0.25);\n z-index: var(--sf-z-index-controls);\n border-radius: var(--sf-border-radius-md) var(--sf-border-radius-md) 0 0;\n cursor: pointer;\n}\n\n/* Show slightly thicker progress bar on hover for better UX */\n.sf-video-container__controls:hover {\n height: 5px;\n}\n\n/* Progress indicator */\n.sf-video-container__progress {\n height: 100%;\n background: rgba(255, 255, 255, 0.8);\n width: 0%;\n transition: width 0.1s linear;\n border-radius: var(--sf-border-radius-md) 0 0 0;\n cursor: pointer;\n transform-origin: left;\n}\n\n/* Mute button */\n.sf-video-container__mute-button {\n position: absolute;\n top: calc(8px + var(--sf-minimize-button-size) + 6px);\n right: 6px;\n width: var(--sf-mute-button-size);\n height: var(--sf-mute-button-size);\n background-color: transparent;\n border-radius: var(--sf-border-radius-circle);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n z-index: var(--sf-z-index-controls);\n color: white;\n border: none;\n font-size: calc(var(--sf-font-size-md) + 2px);\n transition: all var(--sf-transition-normal);\n text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\n opacity: 0;\n}\n\n/* Mute button hover state */\n.sf-video-container__mute-button:hover {\n transform: scale(1.1);\n}\n\n/* Show mute button on container hover */\n.sf-video-container:hover .sf-video-container__mute-button {\n opacity: 1;\n}\n\n/* CC button */\n.sf-video-container__cc-button {\n position: absolute;\n top: calc(8px + var(--sf-minimize-button-size) + 6px + var(--sf-mute-button-size) + 6px);\n right: 6px;\n width: var(--sf-cc-button-size);\n height: var(--sf-cc-button-size);\n background-color: transparent;\n border-radius: 50%; /* Ensure perfect circle */\n padding: 0; /* Remove default button padding */\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n z-index: var(--sf-z-index-controls);\n color: white;\n border: none;\n font-size: calc(var(--sf-font-size-md) + 2px);\n transition: all var(--sf-transition-normal);\n text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\n opacity: 0;\n}\n\n.sf-video-container__cc-button svg {\n display: block;\n margin: auto;\n width: 60%;\n height: 60%;\n}\n\n/* CC button hover state */\n.sf-video-container__cc-button:hover {\n transform: scale(1.1);\n}\n\n/* Hide mute and cc buttons in autoplayBlocked and idleMode states */\n.sf-player--autoplayBlocked .sf-video-container__mute-button,\n.sf-player--autoplayBlocked .sf-video-container__cc-button,\n.sf-player--idleMode .sf-video-container__mute-button,\n.sf-player--idleMode .sf-video-container__cc-button {\n display: none !important;\n}\n\n/* Show mute and cc buttons on hover in playing/paused states */\n.sf-player--playing .sf-video-container:hover .sf-video-container__mute-button,\n.sf-player--playing .sf-video-container:hover .sf-video-container__cc-button,\n.sf-player--paused .sf-video-container:hover .sf-video-container__mute-button,\n.sf-player--paused .sf-video-container:hover .sf-video-container__cc-button {\n opacity: 1;\n} ";
|
|
3724
|
+
const componentsPlayerCss = "/* \n * Player component styles for the Saltfish playlist Player\n * Following BEM naming convention\n */\n\n/* Main player container */\n.sf-player {\n border-radius: var(--sf-border-radius-lg);\n box-shadow: 0 25px 50px rgba(0, 0, 0, 0.45), 0 10px 20px rgba(0, 0, 0, 0.3), 0 0 0 2px rgba(255, 255, 255, 0.08);\n transition: all var(--sf-transition-slow);\n position: relative;\n backdrop-filter: blur(10px);\n -webkit-backdrop-filter: blur(10px);\n opacity: 0;\n transition: opacity 0.3s ease-in-out;\n}\n\n/* Player visible state - show with fade in */\n.sf-player--visible {\n opacity: 1;\n}\n\n/* Dark gradient overlay at bottom of player */\n.sf-player::before {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 33.33%; /* One third of player height */\n background: linear-gradient(to top, rgba(0, 0, 0, 0.8) 0%, rgba(0, 0, 0, 0) 100%);\n pointer-events: none;\n z-index: var(--sf-z-index-overlay);\n border-radius: 8px;\n}\n\n/* Hide gradient overlay when minimized */\n.sf-player--minimized::before {\n display: none;\n}\n\n/* Full-size player state */\n.sf-player:not(.sf-player--minimized) {\n width: var(--sf-player-width);\n height: var(--sf-player-height);\n}\n\n/* Autoplay fallback state - ensure play button is visible */\n.sf-player--waiting-for-user-interaction .sf-controls-container__play-button {\n display: flex !important;\n opacity: 1 !important;\n visibility: visible !important;\n}\n\n/* Also show the center play button in autoplay fallback state */\n.sf-player--waiting-for-user-interaction .sf-player__center-play-button {\n display: flex !important;\n opacity: 1 !important;\n z-index: calc(var(--sf-z-index-controls) + 20) !important; /* Higher z-index to appear above overlay */\n}\n\n/* Make the autoplay fallback state more prominent to indicate need for interaction */\n.sf-player--waiting-for-user-interaction::after {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n pointer-events: none;\n z-index: var(--sf-z-index-overlay);\n}\n\n/* Player state: minimized */\n.sf-player--minimized {\n /* Equal width and height are essential for maintaining a perfect circle when using border-radius: 50% */\n width: var(--sf-player-min-width);\n height: var(--sf-player-min-height);\n border-radius: var(--sf-border-radius-circle);\n box-shadow: 0 15px 30px rgba(0, 0, 0, 0.35), 0 5px 15px rgba(0, 0, 0, 0.25), 0 0 0 2px rgba(255, 255, 255, 0.08);\n cursor: pointer;\n /* Force overriding any inline styles that might be applied */\n max-width: var(--sf-player-min-width) !important;\n max-height: var(--sf-player-min-height) !important;\n min-width: var(--sf-player-min-width) !important;\n min-height: var(--sf-player-min-height) !important;\n}\n\n/* Hide controls when minimized */\n.sf-player--minimized .sf-controls-container {\n display: none;\n}\n\n/* Only show the minimize button when hovering on minimized player */\n.sf-player--minimized .sf-player__minimize-button {\n opacity: 0;\n}\n\n.sf-player--minimized:hover .sf-player__minimize-button {\n opacity: 1;\n}\n\n/* Player root element */\n#sf-player-root {\n position: fixed;\n z-index: var(--sf-z-index-player);\n}\n\n/* Fixed positioning classes */\n.sf-player-root--bottom-left {\n bottom: 20px;\n left: 20px;\n}\n\n.sf-player-root--bottom-right {\n bottom: 20px;\n right: 20px;\n}\n\n/* Player error message */\n.sf-player__error {\n padding: var(--sf-spacing-md);\n color: var(--sf-error-color);\n background-color: var(--sf-error-bg);\n border-radius: var(--sf-border-radius-md);\n margin: var(--sf-spacing-sm);\n font-size: var(--sf-font-size-sm);\n border-left: 4px solid var(--sf-error-color);\n}\n\n/* Minimize button */\n.sf-player__minimize-button {\n position: absolute;\n top: 8px;\n right: 6px;\n width: var(--sf-minimize-button-size);\n height: var(--sf-minimize-button-size);\n background-color: transparent;\n border-radius: var(--sf-border-radius-circle);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n z-index: var(--sf-z-index-controls);\n color: white;\n border: none;\n font-size: calc(var(--sf-font-size-sm) + 4px);\n transition: all var(--sf-transition-normal);\n text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\n opacity: 0;\n}\n\n/* Minimize button hover state */\n.sf-player__minimize-button:hover {\n transform: scale(1.1);\n}\n\n/* Show minimize button on player hover */\n.sf-player:hover .sf-player__minimize-button {\n opacity: 1;\n}\n\n/* Mobile and touch device overrides for minimize button visibility */\n/* Ensure minimize button is always visible on touch devices, even when minimized */\n@media (pointer: coarse) {\n .sf-player__minimize-button {\n opacity: 1 !important;\n z-index: calc(var(--sf-z-index-controls) + 50) !important; /* Much higher z-index for touch devices */\n }\n \n .sf-player--minimized .sf-player__minimize-button {\n opacity: 1 !important;\n z-index: calc(var(--sf-z-index-controls) + 50) !important; /* Much higher z-index for touch devices */\n }\n}\n\n/* Ensure minimize button is always visible on mobile screens under 768px */\n@media (max-width: 768px) {\n .sf-player__minimize-button {\n opacity: 1 !important;\n z-index: calc(var(--sf-z-index-controls) + 50) !important; /* Much higher z-index for mobile */\n /* Position closer to top right corner on mobile */\n top: var(--sf-spacing-xs) !important; /* 4px from top instead of 16px */\n right: var(--sf-spacing-xs) !important; /* 4px from right instead of 12px */\n }\n \n .sf-player--minimized .sf-player__minimize-button {\n opacity: 1 !important;\n z-index: calc(var(--sf-z-index-controls) + 50) !important; /* Much higher z-index for mobile */\n /* Position closer to top right corner on mobile */\n top: var(--sf-spacing-xs) !important; /* 4px from top instead of 16px */\n right: var(--sf-spacing-xs) !important; /* 4px from right instead of 12px */\n }\n}\n\n/* Player title */\n.sf-player__title {\n position: absolute;\n top: var(--sf-spacing-md);\n left: var(--sf-spacing-md);\n color: var(--sf-text-color);\n font-size: var(--sf-font-size-md);\n font-weight: 600;\n z-index: var(--sf-z-index-controls);\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);\n max-width: 70%;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n/* Centered play/pause button overlay */\n.sf-player__center-play-button {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: var(--sf-play-button-size);\n height: var(--sf-play-button-size);\n background-color: rgba(0, 0, 0, 0.5);\n border-radius: var(--sf-border-radius-circle);\n display: none; /* Hidden by default */\n justify-content: center;\n align-items: center;\n z-index: calc(var(--sf-z-index-controls) + 10); /* Ensure higher z-index than other elements */\n color: white;\n border: none;\n font-size: var(--sf-control-button-size);\n cursor: pointer;\n transition: transform var(--sf-transition-normal), background-color var(--sf-transition-normal);\n backdrop-filter: blur(3px);\n -webkit-backdrop-filter: blur(3px);\n box-shadow: 0 15px 30px rgba(0, 0, 0, 0.5), 0 5px 15px rgba(0, 0, 0, 0.3), 0 0 0 2px rgba(255, 255, 255, 0.08);\n pointer-events: auto; /* Enable pointer events to capture clicks */\n}\n\n/* Center play button visible state */\n.sf-player__center-play-button--visible {\n display: flex !important;\n}\n\n/* Center play button prominent state (for autoplay blocked, idle mode) */\n.sf-player__center-play-button--prominent {\n opacity: 1 !important;\n pointer-events: auto !important;\n}\n\n/* Center play button hover state */\n.sf-player__center-play-button:hover {\n transform: translate(-50%, -50%) scale(1.1);\n background-color: rgba(0, 0, 0, 0.7);\n}\n\n/* Hide center play button in minimized state */\n.sf-player--minimized .sf-player__center-play-button {\n display: none !important;\n}\n\n/* Center play button with adjustment for 3+ buttons */\n.sf-player__center-play-button--with-many-buttons {\n transform: translate(-50%, -85%) !important; /* Move up by adjusting Y offset */\n}\n\n/* Exit button for minimized mode */\n.sf-player__exit-button {\n position: absolute;\n top: -22px; /* Position it above the player */\n right: 0;\n width: 20px;\n height: 20px;\n background-color: var(--sf-button-bg);\n border-radius: var(--sf-border-radius-circle);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n z-index: var(--sf-z-index-controls);\n color: white;\n border: none;\n font-size: var(--sf-font-size-md);\n transition: all var(--sf-transition-normal);\n text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\n box-shadow: 0 5px 15px rgba(0, 0, 0, 0.35);\n}\n\n/* Exit button hover state */\n.sf-player__exit-button:hover {\n transform: scale(1.1);\n background-color: var(--sf-button-hover-bg);\n}\n\n/* Show exit button on minimized player hover */\n.sf-player--minimized:hover .sf-player__exit-button {\n opacity: 1;\n}\n\n/* Saltfish logo */\n.sf-player__logo {\n position: absolute;\n bottom: var(--sf-spacing-xs);\n left: 0;\n right: 0;\n height: 18px;\n z-index: var(--sf-z-index-controls);\n opacity: 0.7;\n transition: opacity var(--sf-transition-normal);\n cursor: pointer;\n display: flex;\n justify-content: center;\n align-items: center;\n}\n\n.sf-player__logo svg {\n width: 55px;\n height: 20px;\n}\n\n/* Logo hover state */\n.sf-player:hover .sf-player__logo {\n opacity: 0.9;\n}\n\n/* Hide logo when minimized */\n.sf-player--minimized .sf-player__logo {\n display: none;\n} ";
|
|
3725
|
+
const componentsVideoCss = "/* \n * Video component styles for the Saltfish playlist Player\n * Following BEM naming convention\n */\n\n/* Video container */\n.sf-video-container {\n position: relative;\n width: 100%;\n height: 100%;\n border-radius: var(--sf-border-radius-md);\n overflow: hidden;\n pointer-events: auto; /* Ensure clicks on video container are captured */\n background-color: #000; /* Fallback background for audio-only mode */\n}\n\n/* Audio fallback poster image */\n.sf-video-container--audio-fallback {\n background-size: cover;\n background-position: center;\n background-repeat: no-repeat;\n background-image: var(--sf-audio-poster-url, none);\n}\n\n/* Audio fallback overlay */\n.sf-audio-fallback-overlay {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n background: rgba(0, 0, 0, 0.6);\n z-index: 2;\n pointer-events: none;\n}\n\n.sf-audio-fallback-overlay__icon {\n width: 60px;\n height: 60px;\n margin-bottom: 16px;\n color: white;\n opacity: 0.9;\n}\n\n.sf-audio-fallback-overlay__text {\n color: white;\n font-size: 14px;\n text-align: center;\n padding: 0 20px;\n text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);\n opacity: 0.9;\n}\n\n/* Video element */\n.sf-video-container__video {\n width: 100%;\n height: 100%;\n object-fit: cover;\n /* Ensure video is visible on mobile */\n display: block;\n /* Add explicit positioning to ensure video is visible */\n position: relative;\n z-index: 1;\n}\n\n/* Video blur effect (for end-of-video transitions) */\n.sf-video-container__video--blurred {\n filter: blur(3px);\n transition: filter 0.3s ease-out;\n}\n\n\n\n/* Mobile-specific video styles */\n@media (max-width: 768px) {\n \n .sf-video-container__video {\n /* Force video dimensions on mobile */\n width: 100% !important;\n height: 100% !important;\n object-fit: cover !important;\n /* Prevent video from being hidden */\n opacity: 1 !important;\n visibility: visible !important;\n /* Ensure video is above any potential overlays */\n z-index: 10 !important;\n position: relative !important;\n }\n \n /* Make controls more touch-friendly on mobile */\n .sf-video-container__controls {\n height: 5px; /* Thicker on mobile for easier touch */\n }\n \n .sf-video-container__mute-button {\n /* Use CSS variable for consistent sizing */\n min-width: var(--sf-mute-button-size) !important;\n min-height: var(--sf-mute-button-size) !important;\n opacity: 1; /* Always visible on mobile (no hover) */\n }\n \n .sf-video-container__cc-button {\n /* Use CSS variable for consistent sizing */\n min-width: var(--sf-cc-button-size) !important;\n min-height: var(--sf-cc-button-size) !important;\n opacity: 1; /* Always visible on mobile (no hover) */\n }\n}\n\n/* Touch device specific styles */\n@media (pointer: coarse) {\n .sf-video-container__controls:hover {\n height: 5px; /* Keep consistent height on touch devices */\n }\n \n .sf-video-container__mute-button {\n opacity: 1; /* Always show on touch devices */\n }\n \n .sf-video-container__cc-button {\n opacity: 1; /* Always show on touch devices */\n }\n \n .sf-video-container:hover .sf-video-container__mute-button {\n opacity: 1;\n }\n}\n\n/* Video in minimized state */\n.sf-player--minimized .sf-video-container {\n border-radius: var(--sf-border-radius-circle);\n cursor: pointer;\n z-index: var(--sf-z-index-base);\n width: 100%;\n height: 100%;\n}\n\n.sf-player--minimized .sf-video-container__video {\n border-radius: var(--sf-border-radius-circle);\n object-fit: cover;\n width: 100%;\n height: 100%;\n}\n\n/* Hide progress bar in minimized state */\n.sf-player--minimized .sf-video-container__controls {\n display: none !important;\n}\n\n/* Also hide mute button in minimized state */\n.sf-player--minimized .sf-video-container__mute-button {\n display: none !important;\n}\n\n/* Also hide CC button in minimized state */\n.sf-player--minimized .sf-video-container__cc-button {\n display: none !important;\n}\n\n/* Progress bar container */\n.sf-video-container__controls {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 3px;\n background-color: rgba(255, 255, 255, 0.25);\n z-index: var(--sf-z-index-controls);\n border-radius: var(--sf-border-radius-md) var(--sf-border-radius-md) 0 0;\n cursor: pointer;\n}\n\n/* Show slightly thicker progress bar on hover for better UX */\n.sf-video-container__controls:hover {\n height: 5px;\n}\n\n/* Progress indicator */\n.sf-video-container__progress {\n height: 100%;\n background: rgba(255, 255, 255, 0.8);\n width: 0%;\n transition: width 0.1s linear;\n border-radius: var(--sf-border-radius-md) 0 0 0;\n cursor: pointer;\n transform-origin: left;\n}\n\n/* Mute button */\n.sf-video-container__mute-button {\n position: absolute;\n top: calc(8px + var(--sf-minimize-button-size) + 6px);\n right: 6px;\n width: var(--sf-mute-button-size);\n height: var(--sf-mute-button-size);\n background-color: transparent;\n border-radius: var(--sf-border-radius-circle);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n z-index: var(--sf-z-index-controls);\n color: white;\n border: none;\n font-size: calc(var(--sf-font-size-md) + 2px);\n transition: all var(--sf-transition-normal);\n text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\n opacity: 0;\n}\n\n/* Mute button hover state */\n.sf-video-container__mute-button:hover {\n transform: scale(1.1);\n}\n\n/* Show mute button on container hover */\n.sf-video-container:hover .sf-video-container__mute-button {\n opacity: 1;\n}\n\n/* CC button */\n.sf-video-container__cc-button {\n position: absolute;\n top: calc(8px + var(--sf-minimize-button-size) + 6px + var(--sf-mute-button-size) + 6px);\n right: 6px;\n width: var(--sf-cc-button-size);\n height: var(--sf-cc-button-size);\n background-color: transparent;\n border-radius: 50%; /* Ensure perfect circle */\n padding: 0; /* Remove default button padding */\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n z-index: var(--sf-z-index-controls);\n color: white;\n border: none;\n font-size: calc(var(--sf-font-size-md) + 2px);\n transition: all var(--sf-transition-normal);\n text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\n opacity: 0;\n}\n\n.sf-video-container__cc-button svg {\n display: block;\n margin: auto;\n width: 60%;\n height: 60%;\n}\n\n/* CC button hover state */\n.sf-video-container__cc-button:hover {\n transform: scale(1.1);\n}\n\n/* Hide mute and cc buttons in autoplayBlocked and idleMode states */\n.sf-player--autoplayBlocked .sf-video-container__mute-button,\n.sf-player--autoplayBlocked .sf-video-container__cc-button,\n.sf-player--idleMode .sf-video-container__mute-button,\n.sf-player--idleMode .sf-video-container__cc-button {\n display: none !important;\n}\n\n/* Show mute and cc buttons on hover in playing/paused states */\n.sf-player--playing .sf-video-container:hover .sf-video-container__mute-button,\n.sf-player--playing .sf-video-container:hover .sf-video-container__cc-button,\n.sf-player--paused .sf-video-container:hover .sf-video-container__mute-button,\n.sf-player--paused .sf-video-container:hover .sf-video-container__cc-button {\n opacity: 1;\n} ";
|
|
3726
3726
|
const componentsControlsCss = "/* \n * Controls component styles for the Saltfish playlist Player\n * Following BEM naming convention\n */\n\n/* Main controls container */\n.sf-controls-container {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n display: flex;\n justify-content: center;\n align-items: center;\n background-color: transparent;\n z-index: var(--sf-z-index-controls);\n pointer-events: auto;\n}\n\n/* Play button */\n.sf-controls-container__play-button {\n background-color: rgba(0, 0, 0, 0.6);\n border: none;\n color: var(--sf-text-color);\n font-size: var(--sf-control-button-size);\n cursor: pointer;\n width: var(--sf-play-button-size);\n height: var(--sf-play-button-size);\n border-radius: var(--sf-border-radius-circle);\n display: flex;\n justify-content: center;\n align-items: center;\n transition: transform var(--sf-transition-normal), background-color var(--sf-transition-normal);\n padding-left: 4px; /* Optical centering for play icon */\n}\n\n/* Button hover state */\n.sf-controls-container__play-button:hover {\n background-color: rgba(0, 0, 0, 0.4);\n transform: scale(1.1);\n}\n\n/* Button container for interactive buttons */\n.sf-controls-container__buttons {\n display: flex;\n justify-content: center;\n align-items: center;\n gap: var(--sf-spacing-md);\n}\n\n/* Interactive button */\n.sf-controls-container__interactive-button {\n background-color: rgba(255, 255, 255, 0.2);\n backdrop-filter: blur(8px);\n -webkit-backdrop-filter: blur(8px);\n color: white;\n border: none;\n border-radius: var(--sf-border-radius-md);\n padding: var(--sf-spacing-xs) var(--sf-spacing-md);\n font-size: var(--sf-font-size-sm);\n cursor: pointer;\n transition: background-color var(--sf-transition-normal), transform var(--sf-transition-fast);\n box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);\n}\n\n.sf-controls-container__interactive-button:hover {\n background-color: rgba(255, 255, 255, 0.3);\n transform: translateY(-2px);\n}\n\n/* \n * Choice buttons container and buttons - positioned inside player\n */\n\n/* Choice buttons container - positioned inside the player at the bottom */\n.sf-choice-buttons-container {\n position: absolute;\n bottom: var(--sf-spacing-xl);\n left: 50%;\n transform: translateX(-50%);\n width: calc(100% - var(--sf-spacing-lg));\n max-width: calc(100% - var(--sf-spacing-lg));\n z-index: calc(var(--sf-z-index-controls) + 1);\n gap: var(--sf-spacing-sm);\n pointer-events: auto;\n align-items: center;\n display: flex;\n flex-direction: column;\n /* Ensure container is fully transparent */\n background: transparent;\n border: none;\n outline: none;\n}\n\n/* Choice buttons container with scrolling for 4+ buttons */\n.sf-choice-buttons-container--scrollable {\n max-height: 132px; /* Show ~3 buttons with gaps (3 * 36px button + 3 * 8px gap) */\n overflow-y: auto;\n overflow-x: hidden;\n scrollbar-width: thin; /* Show thin scrollbar in Firefox */\n scrollbar-color: rgba(255, 255, 255, 0.2) transparent; /* More transparent Firefox scrollbar */\n scroll-behavior: smooth;\n /* Important: Use block display for scrollable container */\n display: block !important;\n}\n\n/* Style webkit scrollbar to be visible but subtle */\n.sf-choice-buttons-container--scrollable::-webkit-scrollbar {\n width: 4px;\n}\n\n.sf-choice-buttons-container--scrollable::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.sf-choice-buttons-container--scrollable::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.2); /* More transparent */\n border-radius: 2px;\n}\n\n.sf-choice-buttons-container--scrollable::-webkit-scrollbar-thumb:hover {\n background: rgba(255, 255, 255, 0.4); /* Still subtle on hover */\n}\n\n/* Removed fade gradient to keep container fully transparent */\n\n/* Choice button styles - solid rounded buttons matching the image */\n.sf-choice-button {\n width: 100%;\n max-width: none;\n background: rgba(0, 0, 0, 4);\n backdrop-filter: blur(8px);\n -webkit-backdrop-filter: blur(8px);\n color: white;\n border: none;\n border-radius: 24px; /* More rounded for pill shape */\n padding: var(--sf-spacing-md) var(--sf-spacing-md);\n font-size: 12px;\n cursor: pointer;\n transition: all 0.2s ease;\n text-align: center;\n outline: none;\n font-family: inherit;\n margin-bottom: 0;\n position: relative;\n overflow: hidden;\n opacity: 0; /* Start hidden for animation */\n pointer-events: none;\n /* Animation will be triggered by JavaScript when video reaches 90% */\n}\n\n/* Add margin between buttons in scrollable container */\n.sf-choice-buttons-container--scrollable .sf-choice-button {\n margin-bottom: var(--sf-spacing-sm);\n}\n\n/* Remove margin from last button */\n.sf-choice-buttons-container--scrollable .sf-choice-button:last-child {\n margin-bottom: 0;\n}\n\n/* Hover state for buttons */\n.sf-choice-button:hover {\n background: rgba(0, 0, 0, 0.9);\n transform: translateY(-2px);\n box-shadow: 0 6px 16px rgba(0, 0, 0, 0.8);\n}\n\n/* Active state for all buttons */\n.sf-choice-button:active {\n transform: translateY(0) scale(0.98);\n transition: all 0.1s ease;\n}\n\n/* Remove specific action type styling - use consistent dark buttons */\n.sf-choice-button--goto,\n.sf-choice-button--url,\n.sf-choice-button--next,\n.sf-choice-button--dom,\n.sf-choice-button--function {\n background: rgba(0, 0, 0, 0.4);\n border: none;\n}\n\n.sf-choice-button--goto:hover,\n.sf-choice-button--url:hover,\n.sf-choice-button--next:hover,\n.sf-choice-button--dom:hover,\n.sf-choice-button--function:hover {\n background: rgba(0, 0, 0, 0.9);\n transform: translateY(-2px);\n box-shadow: 0 6px 16px rgba(0, 0, 0, 0.4);\n}\n\n/* Hide choice buttons in minimized state */\n.sf-player--minimized .sf-choice-buttons-container {\n display: none;\n}\n\n/* Hide choice buttons in autoplayBlocked and idleMode states */\n.sf-player--autoplayBlocked .sf-choice-buttons-container,\n.sf-player--idleMode .sf-choice-buttons-container {\n display: none !important;\n}\n\n/* Smaller mobile screens - maintain same layout but with tighter spacing */\n@media (max-width: 480px) {\n .sf-choice-buttons-container {\n bottom: var(--sf-spacing-sm);\n width: calc(100% - var(--sf-spacing-md));\n max-width: calc(100% - var(--sf-spacing-md));\n gap: calc(var(--sf-spacing-xs) + 2px);\n }\n \n .sf-choice-button {\n padding: var(--sf-spacing-sm) var(--sf-spacing-sm);\n font-size: 11px;\n border-radius: 20px;\n }\n}\n\n/* Touch device specific adjustments */\n@media (pointer: coarse) {\n .sf-choice-buttons-container {\n gap: var(--sf-spacing-sm);\n }\n \n .sf-choice-button {\n min-height: 44px; /* Apple's recommended minimum touch target size */\n padding: var(--sf-spacing-md) var(--sf-spacing-md);\n }\n}\n\n/* Button fade-in animation */\n@keyframes buttonFadeIn {\n from {\n opacity: 0;\n transform: translateY(10px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n/* Animation class that will be added by JavaScript at 90% video progress */\n.sf-choice-button.sf-show-button {\n animation: buttonFadeIn 0.3s ease-out forwards;\n pointer-events: auto;\n}\n\n/* Staggered animation delays for multiple buttons when shown */\n.sf-choice-button.sf-show-button:nth-child(1) {\n animation-delay: 0s;\n}\n\n.sf-choice-button.sf-show-button:nth-child(2) {\n animation-delay: 0.15s;\n}\n\n.sf-choice-button.sf-show-button:nth-child(3) {\n animation-delay: 0.3s;\n}\n\n.sf-choice-button.sf-show-button:nth-child(4) {\n animation-delay: 0.45s;\n}\n\n.sf-choice-button.sf-show-button:nth-child(5) {\n animation-delay: 0.6s;\n}\n\n.sf-choice-button.sf-show-button:nth-child(6) {\n animation-delay: 0.75s;\n}\n\n.sf-choice-button.sf-show-button:nth-child(7) {\n animation-delay: 0.9s;\n}\n\n.sf-choice-button.sf-show-button:nth-child(8) {\n animation-delay: 1.05s;\n}\n\n/* Scroll indicator arrow */\n.sf-scroll-indicator {\n position: absolute;\n bottom: calc(var(--sf-spacing-xl) - 25px);\n left: 50%;\n transform: translateX(-50%);\n color: rgba(255, 255, 255, 0.6);\n font-size: 20px;\n pointer-events: none;\n z-index: calc(var(--sf-z-index-controls) + 2);\n transition: opacity 0.3s ease;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n opacity: 0; /* Start hidden */\n}\n\n/* Show scroll indicator with animation - appears after buttons */\n.sf-scroll-indicator.sf-show-scroll-indicator {\n animation: scrollIndicatorFadeIn 0.4s ease-out 1.2s forwards, bounceArrow 1.5s ease-in-out 1.6s infinite;\n}\n\n/* Hide arrow when scrolled to bottom */\n.sf-scroll-indicator--hidden {\n opacity: 0;\n}\n\n/* Fade in animation for scroll indicator */\n@keyframes scrollIndicatorFadeIn {\n from {\n opacity: 0;\n transform: translateX(-50%) translateY(-10px);\n }\n to {\n opacity: 1;\n transform: translateX(-50%) translateY(0);\n }\n}\n\n/* Bounce animation for the arrow */\n@keyframes bounceArrow {\n 0%, 100% {\n transform: translateX(-50%) translateY(0);\n }\n 50% {\n transform: translateX(-50%) translateY(5px);\n }\n}\n\n/* Hide scroll indicator in minimized state */\n.sf-player--minimized .sf-scroll-indicator {\n display: none;\n}\n\n/* Hide scroll indicator in autoplayBlocked and idleMode states */\n.sf-player--autoplayBlocked .sf-scroll-indicator,\n.sf-player--idleMode .sf-scroll-indicator {\n display: none !important;\n} ";
|
|
3727
3727
|
const componentsTranscriptCss = "/* \n * Transcript component styles for the Saltfish Playlist Player\n * Following BEM naming convention\n */\n\n/* Transcript container */\n.sf-transcript {\n position: absolute;\n bottom: 40px; /* Above the progress bar */\n left: 0;\n right: 0;\n max-height: 200px;\n background: transparent;\n margin: 0 var(--sf-spacing-md);\n overflow: hidden;\n z-index: var(--sf-z-index-overlay);\n opacity: 0;\n transform: translateY(20px);\n transition: all 0.3s ease-out;\n pointer-events: none;\n}\n\n/* Visible state */\n.sf-transcript--visible {\n opacity: 1;\n transform: translateY(0);\n pointer-events: auto;\n}\n\n/* Transcript content */\n.sf-transcript__content {\n max-height: 180px;\n overflow: visible;\n padding: 0;\n}\n\n/* Webkit scrollbar styling */\n.sf-transcript__content::-webkit-scrollbar {\n width: 4px;\n}\n\n.sf-transcript__content::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.sf-transcript__content::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.3);\n border-radius: 2px;\n}\n\n.sf-transcript__content::-webkit-scrollbar-thumb:hover {\n background: rgba(255, 255, 255, 0.5);\n}\n\n/* Word-by-word display container */\n.sf-transcript__word-container {\n display: flex;\n justify-content: center;\n align-items: center;\n gap: 0; /* Remove flex gap - spacing handled by margin on preview word */\n min-height: 60px;\n padding: 0;\n}\n\n/* Individual word styling */\n.sf-transcript__word {\n color: rgba(255, 255, 255, 0.9);\n font-size: var(--sf-font-size-lg);\n font-weight: 600;\n line-height: 1.2;\n transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);\n transform: translateY(0);\n filter: blur(0px);\n opacity: 1;\n text-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);\n}\n\n/* Active word (currently speaking) */\n.sf-transcript__word--active {\n opacity: 1;\n filter: blur(0px);\n transform: translateY(0) scale(1);\n color: rgba(255, 255, 255, 1);\n font-weight: 600;\n}\n\n/* Preview word (clean, unblurred when shown) */\n.sf-transcript__word--preview {\n opacity: 0.8;\n filter: blur(0px);\n transform: translateY(0) scale(0.98);\n color: rgba(255, 255, 255, 0.8);\n font-weight: 400;\n margin-left: 0.2em; /* Minimal spacing - just enough for a natural gap */\n}\n\n/* Legacy segment styling (kept for compatibility) */\n.sf-transcript__segment {\n color: rgba(255, 255, 255);\n font-size: var(--sf-font-size-sm);\n line-height: 1.4;\n padding: var(--sf-spacing-xs) 0;\n cursor: pointer;\n transition: all 0.2s ease;\n padding-left: var(--sf-spacing-xs);\n padding-right: var(--sf-spacing-xs);\n}\n\n/* CC button styling removed - now handled via icon toggling */\n\n/* Mobile responsive styles */\n@media (max-width: 768px) {\n .sf-transcript {\n bottom: 50px; /* More space on mobile */\n margin: 0 var(--sf-spacing-sm);\n max-height: 150px; /* Smaller on mobile */\n }\n \n .sf-transcript__content {\n max-height: 130px;\n padding: var(--sf-spacing-sm);\n }\n \n .sf-transcript__word-container {\n min-height: 50px;\n padding: var(--sf-spacing-sm);\n gap: var(--sf-spacing-xs);\n }\n \n .sf-transcript__word {\n font-size: var(--sf-font-size-md);\n font-weight: 500;\n }\n \n .sf-transcript__segment {\n font-size: var(--sf-font-size-xs);\n padding: var(--sf-spacing-xs) var(--sf-spacing-sm);\n }\n}\n\n/* Touch device optimizations */\n@media (pointer: coarse) {\n .sf-transcript__segment {\n padding: var(--sf-spacing-sm) var(--sf-spacing-xs);\n min-height: 44px; /* Larger touch target */\n display: flex;\n align-items: center;\n }\n}\n\n/* Hide transcript in minimized state */\n.sf-player--minimized .sf-transcript {\n display: none !important;\n}\n\n/* Hide transcript in autoplayBlocked and idleMode states */\n.sf-player--autoplayBlocked .sf-transcript,\n.sf-player--idleMode .sf-transcript {\n display: none !important;\n}\n\n/* Animation for transcript appearance */\n@keyframes transcriptFadeIn {\n from {\n opacity: 0;\n transform: translateY(20px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes transcriptFadeOut {\n from {\n opacity: 1;\n transform: translateY(0);\n }\n to {\n opacity: 0;\n transform: translateY(20px);\n }\n}";
|
|
3728
3728
|
const componentsErrorCss = "/* \n * Error Display component styles for the Saltfish playlist Player\n * Clean and subtle full-widget error overlay\n */\n\n/* Error display overlay - covers full widget */\n.sf-error-display {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: rgba(0, 0, 0, 0.75);\n backdrop-filter: blur(6px);\n -webkit-backdrop-filter: blur(6px);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: calc(var(--sf-z-index-controls) + 30);\n border-radius: var(--sf-border-radius-lg);\n opacity: 0;\n transition: opacity var(--sf-transition-slow);\n pointer-events: auto;\n}\n\n/* Error display visible state */\n.sf-error-display--visible {\n opacity: 1;\n}\n\n/* Error content container */\n.sf-error-display__content {\n background-color: rgba(20, 20, 20, 0.9);\n border-radius: var(--sf-border-radius-md);\n padding: var(--sf-spacing-lg) var(--sf-spacing-xl);\n backdrop-filter: blur(10px);\n -webkit-backdrop-filter: blur(10px);\n border: 1px solid rgba(255, 255, 255, 0.08);\n transform: translateY(8px);\n transition: transform var(--sf-transition-slow);\n max-width: 85%;\n text-align: center;\n}\n\n/* Error content visible animation */\n.sf-error-display--visible .sf-error-display__content {\n transform: translateY(0);\n}\n\n/* Error message */\n.sf-error-display__message {\n color: rgba(255, 255, 255, 0.95);\n font-size: var(--sf-font-size-md);\n line-height: 1.5;\n margin: 0;\n text-align: center;\n font-weight: 500;\n}\n\n/* Mobile responsive adjustments */\n@media (max-width: 768px) {\n .sf-error-display__content {\n padding: var(--sf-spacing-md) var(--sf-spacing-lg);\n max-width: 90%;\n }\n\n .sf-error-display__message {\n font-size: var(--sf-font-size-sm);\n }\n}\n\n/* Minimized player state adjustments */\n.sf-player--minimized .sf-error-display__content {\n padding: var(--sf-spacing-sm) var(--sf-spacing-md);\n max-width: 80%;\n}\n\n.sf-player--minimized .sf-error-display__message {\n font-size: var(--sf-font-size-sm);\n font-weight: 400;\n}\n\n/* High contrast mode support */\n@media (prefers-contrast: high) {\n .sf-error-display__content {\n background-color: rgba(0, 0, 0, 0.95);\n border: 2px solid rgba(255, 255, 255, 0.3);\n }\n\n .sf-error-display__message {\n color: rgba(255, 255, 255, 0.95);\n }\n}\n\n/* Reduced motion support */\n@media (prefers-reduced-motion: reduce) {\n .sf-error-display,\n .sf-error-display__content {\n transition: none;\n }\n}";
|
|
3729
3729
|
const componentsLoadingCss = "/**\n * Loading spinner styles\n */\n\n.sf-loading-spinner {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background-color: rgba(255, 255, 255, 0.95);\n backdrop-filter: blur(2px);\n z-index: 100;\n border-radius: 12px;\n opacity: 1 !important; /* Always visible when shown, overrides parent opacity */\n}\n\n.sf-loading-spinner__content {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n padding: 24px;\n}\n\n.sf-loading-spinner__icon {\n display: flex;\n align-items: center;\n justify-content: center;\n color: #000000;\n opacity: 0.9;\n}\n\n.sf-loading-spinner__icon svg {\n width: 60px;\n height: 60px;\n /* Remove the rotation animation since we now have internal SVG animation */\n}\n\n.sf-loading-spinner__text {\n color: #333333;\n font-size: 14px;\n font-weight: 500;\n text-align: center;\n opacity: 0.8;\n letter-spacing: 0.5px;\n}\n\n/* CSS keyframe animation removed - using SVG animateTransform instead */\n\n/* Responsive adjustments */\n@media (max-width: 480px) {\n .sf-loading-spinner__content {\n padding: 20px;\n gap: 10px;\n }\n \n .sf-loading-spinner__icon svg {\n width: 50px;\n height: 50px;\n }\n \n .sf-loading-spinner__text {\n font-size: 13px;\n }\n}";
|
|
3730
|
+
const componentsCursorCss = "/*\n * Cursor animation component styles for the Saltfish playlist Player\n * CSP-compliant: All styles use CSS classes and CSS custom properties instead of inline styles\n */\n\n/* Base cursor element */\n.sf-cursor {\n position: fixed;\n top: 0;\n left: 0;\n width: 36px;\n height: 36px;\n z-index: 9999999;\n pointer-events: none;\n display: none;\n will-change: transform;\n transform: var(--sf-cursor-transform, translate(0, 0));\n opacity: var(--sf-cursor-opacity, 1);\n}\n\n.sf-cursor--visible {\n display: block;\n}\n\n/* Selection element */\n.sf-selection {\n position: fixed;\n pointer-events: none;\n display: none;\n z-index: 9999998;\n border: 2px solid #ff7614;\n background: rgba(255, 118, 20, 0.1);\n left: var(--sf-selection-left, 0);\n top: var(--sf-selection-top, 0);\n width: var(--sf-selection-width, 0);\n height: var(--sf-selection-height, 0);\n}\n\n.sf-selection--visible {\n display: block;\n}\n\n/* Flashlight overlay */\n.sf-flashlight-overlay {\n position: fixed;\n top: 0;\n left: 0;\n width: 100vw;\n height: 100vh;\n pointer-events: none;\n z-index: 999997;\n display: none;\n background: var(--sf-flashlight-bg, radial-gradient(circle 150px at 50% 50%, transparent 0%, rgba(0, 0, 0, 0.4) 100%));\n clip-path: var(--sf-flashlight-clip, none);\n}\n\n.sf-flashlight-overlay--visible {\n display: block;\n}\n";
|
|
3730
3731
|
const animationsTransitionsCss = "/* \n * Transitions and animations for Saltfish playlist Player\n */\n\n/* Fade in animation */\n@keyframes sf-fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n.sf-fade-in {\n animation: sf-fade-in 0.3s ease-in-out forwards;\n}\n\n/* Slide in from bottom animation */\n@keyframes sf-slide-in-bottom {\n from { transform: translateY(100%); opacity: 0; }\n to { transform: translateY(0); opacity: 1; }\n}\n\n.sf-slide-in-bottom {\n animation: sf-slide-in-bottom 0.3s cubic-bezier(0.25, 0.8, 0.25, 1) forwards;\n}\n\n/* Slide in from right animation */\n@keyframes sf-slide-in-right {\n from { transform: translateX(100%); opacity: 0; }\n to { transform: translateX(0); opacity: 1; }\n}\n\n.sf-slide-in-right {\n animation: sf-slide-in-right 0.3s cubic-bezier(0.25, 0.8, 0.25, 1) forwards;\n}\n\n/* Scale in animation */\n@keyframes sf-scale-in {\n from { transform: scale(0.8); opacity: 0; }\n to { transform: scale(1); opacity: 1; }\n}\n\n.sf-scale-in {\n animation: sf-scale-in 0.3s cubic-bezier(0.25, 0.8, 0.25, 1) forwards;\n}\n\n/* Scale out animation */\n@keyframes sf-scale-out {\n from { transform: scale(1); opacity: 1; }\n to { transform: scale(0.8); opacity: 0; }\n}\n\n.sf-scale-out {\n animation: sf-scale-out 0.3s cubic-bezier(0.25, 0.8, 0.25, 1) forwards;\n} ";
|
|
3731
3732
|
const getPlayerStyles = () => `
|
|
3732
3733
|
${baseResetCss}
|
|
3733
3734
|
${baseVariablesCss}
|
|
3734
|
-
|
|
3735
|
+
|
|
3735
3736
|
${componentsPlayerCss}
|
|
3736
3737
|
${componentsVideoCss}
|
|
3737
3738
|
${componentsControlsCss}
|
|
3738
3739
|
${componentsTranscriptCss}
|
|
3739
3740
|
${componentsErrorCss}
|
|
3740
3741
|
${componentsLoadingCss}
|
|
3741
|
-
|
|
3742
|
+
${componentsCursorCss}
|
|
3743
|
+
|
|
3742
3744
|
${animationsTransitionsCss}
|
|
3743
3745
|
`;
|
|
3744
3746
|
class ShadowDOMManager {
|
|
@@ -3759,9 +3761,15 @@ class ShadowDOMManager {
|
|
|
3759
3761
|
this.container.appendChild(document.createTextNode(""));
|
|
3760
3762
|
document.body.appendChild(this.container);
|
|
3761
3763
|
this.shadowRoot = this.container.attachShadow({ mode: "open" });
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
|
|
3764
|
+
try {
|
|
3765
|
+
const sheet = new CSSStyleSheet();
|
|
3766
|
+
sheet.replaceSync(this.getBaseStyles());
|
|
3767
|
+
this.shadowRoot.adoptedStyleSheets = [sheet];
|
|
3768
|
+
} catch (error2) {
|
|
3769
|
+
this.styleElement = document.createElement("style");
|
|
3770
|
+
this.styleElement.textContent = this.getBaseStyles();
|
|
3771
|
+
this.shadowRoot.appendChild(this.styleElement);
|
|
3772
|
+
}
|
|
3765
3773
|
const rootElement = document.createElement("div");
|
|
3766
3774
|
rootElement.id = "sf-player-root";
|
|
3767
3775
|
this.shadowRoot.appendChild(rootElement);
|
|
@@ -3786,10 +3794,22 @@ class ShadowDOMManager {
|
|
|
3786
3794
|
* Adds a stylesheet to the shadow DOM
|
|
3787
3795
|
*/
|
|
3788
3796
|
addStyles(styles) {
|
|
3789
|
-
if (!this.
|
|
3797
|
+
if (!this.shadowRoot) {
|
|
3790
3798
|
return;
|
|
3791
3799
|
}
|
|
3792
|
-
this.
|
|
3800
|
+
if (this.shadowRoot.adoptedStyleSheets && this.shadowRoot.adoptedStyleSheets.length > 0) {
|
|
3801
|
+
try {
|
|
3802
|
+
const existingSheet = this.shadowRoot.adoptedStyleSheets[0];
|
|
3803
|
+
const currentRules = Array.from(existingSheet.cssRules).map((rule) => rule.cssText).join("\n");
|
|
3804
|
+
existingSheet.replaceSync(currentRules + "\n" + styles);
|
|
3805
|
+
return;
|
|
3806
|
+
} catch (error2) {
|
|
3807
|
+
console.warn("ShadowDOMManager: Failed to append to adoptedStyleSheet:", error2);
|
|
3808
|
+
}
|
|
3809
|
+
}
|
|
3810
|
+
if (this.styleElement) {
|
|
3811
|
+
this.styleElement.textContent += styles;
|
|
3812
|
+
}
|
|
3793
3813
|
}
|
|
3794
3814
|
/**
|
|
3795
3815
|
* Removes the shadow DOM container
|
|
@@ -4217,7 +4237,7 @@ const _TranscriptManager = class _TranscriptManager {
|
|
|
4217
4237
|
}
|
|
4218
4238
|
this.transcriptContainer = document.createElement("div");
|
|
4219
4239
|
this.transcriptContainer.className = "sf-transcript";
|
|
4220
|
-
this.transcriptContainer.
|
|
4240
|
+
this.transcriptContainer.classList.add("sf-hidden");
|
|
4221
4241
|
this.transcriptContent = document.createElement("div");
|
|
4222
4242
|
this.transcriptContent.className = "sf-transcript__content";
|
|
4223
4243
|
if (this.transcriptContainer && this.transcriptContent) {
|
|
@@ -4240,7 +4260,7 @@ const _TranscriptManager = class _TranscriptManager {
|
|
|
4240
4260
|
showTranscript() {
|
|
4241
4261
|
log(`TranscriptManager: showTranscript called, container exists: ${!!this.transcriptContainer}`);
|
|
4242
4262
|
if (this.transcriptContainer) {
|
|
4243
|
-
this.transcriptContainer.
|
|
4263
|
+
this.transcriptContainer.classList.remove("sf-hidden");
|
|
4244
4264
|
this.transcriptContainer.classList.add("sf-transcript--visible");
|
|
4245
4265
|
}
|
|
4246
4266
|
}
|
|
@@ -4250,7 +4270,7 @@ const _TranscriptManager = class _TranscriptManager {
|
|
|
4250
4270
|
hideTranscript() {
|
|
4251
4271
|
log(`TranscriptManager: hideTranscript called, container exists: ${!!this.transcriptContainer}`);
|
|
4252
4272
|
if (this.transcriptContainer) {
|
|
4253
|
-
this.transcriptContainer.
|
|
4273
|
+
this.transcriptContainer.classList.add("sf-hidden");
|
|
4254
4274
|
this.transcriptContainer.classList.remove("sf-transcript--visible");
|
|
4255
4275
|
}
|
|
4256
4276
|
}
|
|
@@ -4263,10 +4283,10 @@ const _TranscriptManager = class _TranscriptManager {
|
|
|
4263
4283
|
return;
|
|
4264
4284
|
}
|
|
4265
4285
|
if (hasTranscript) {
|
|
4266
|
-
this.ccButton.
|
|
4286
|
+
this.ccButton.classList.remove("sf-hidden");
|
|
4267
4287
|
(_a = this.videoManager) == null ? void 0 : _a.updateCCButtonIcon(this.isVisible);
|
|
4268
4288
|
} else {
|
|
4269
|
-
this.ccButton.
|
|
4289
|
+
this.ccButton.classList.add("sf-hidden");
|
|
4270
4290
|
}
|
|
4271
4291
|
}
|
|
4272
4292
|
/**
|
|
@@ -4391,8 +4411,8 @@ class MobilePlaybackHandler extends DevicePlaybackHandler {
|
|
|
4391
4411
|
}
|
|
4392
4412
|
configureControlElement(element) {
|
|
4393
4413
|
const config = this.getControlsConfig();
|
|
4394
|
-
element.style.
|
|
4395
|
-
element.style.
|
|
4414
|
+
element.style.setProperty("min-width", config.buttonMinSize.width);
|
|
4415
|
+
element.style.setProperty("min-height", config.buttonMinSize.height);
|
|
4396
4416
|
}
|
|
4397
4417
|
async handlePlayAttempt(video, hasUserInteracted) {
|
|
4398
4418
|
const store = useSaltfishStore.getState();
|
|
@@ -4547,7 +4567,7 @@ class VideoControlsUI {
|
|
|
4547
4567
|
var _a;
|
|
4548
4568
|
this.lastTimeupdateEvent = Date.now();
|
|
4549
4569
|
if (this.progressBar && ((_a = this.videoElement) == null ? void 0 : _a.paused) === false) {
|
|
4550
|
-
this.progressBar.style.transition
|
|
4570
|
+
this.progressBar.style.setProperty("transition", "width 0.1s linear");
|
|
4551
4571
|
}
|
|
4552
4572
|
if (this.videoElement && !this.buttonsShownAt90Percent && this.videoElement.duration > 0) {
|
|
4553
4573
|
const progress = this.videoElement.currentTime / this.videoElement.duration;
|
|
@@ -4562,7 +4582,7 @@ class VideoControlsUI {
|
|
|
4562
4582
|
*/
|
|
4563
4583
|
__publicField(this, "handleSeeking", () => {
|
|
4564
4584
|
if (this.progressBar) {
|
|
4565
|
-
this.progressBar.style.transition
|
|
4585
|
+
this.progressBar.style.setProperty("transition", "none");
|
|
4566
4586
|
this.updateProgress();
|
|
4567
4587
|
}
|
|
4568
4588
|
});
|
|
@@ -4574,7 +4594,7 @@ class VideoControlsUI {
|
|
|
4574
4594
|
if (!this.videoElement.paused) {
|
|
4575
4595
|
this.updateProgress();
|
|
4576
4596
|
void this.progressBar.offsetWidth;
|
|
4577
|
-
this.progressBar.style.transition
|
|
4597
|
+
this.progressBar.style.setProperty("transition", "width 0.1s linear");
|
|
4578
4598
|
}
|
|
4579
4599
|
}
|
|
4580
4600
|
});
|
|
@@ -4588,8 +4608,8 @@ class VideoControlsUI {
|
|
|
4588
4608
|
const clickPosition = (event.clientX - rect.left) / rect.width;
|
|
4589
4609
|
const seekTime = this.videoElement.duration * clickPosition;
|
|
4590
4610
|
if (this.progressBar) {
|
|
4591
|
-
this.progressBar.style.transition
|
|
4592
|
-
this.progressBar.style.width
|
|
4611
|
+
this.progressBar.style.setProperty("transition", "none");
|
|
4612
|
+
this.progressBar.style.setProperty("width", `${clickPosition * 100}%`);
|
|
4593
4613
|
}
|
|
4594
4614
|
this.callbacks.onSeek(seekTime);
|
|
4595
4615
|
event.preventDefault();
|
|
@@ -4681,8 +4701,8 @@ class VideoControlsUI {
|
|
|
4681
4701
|
this.buttonsShownAt90Percent = false;
|
|
4682
4702
|
this.lastTimeupdateEvent = 0;
|
|
4683
4703
|
if (this.progressBar) {
|
|
4684
|
-
this.progressBar.style.transition
|
|
4685
|
-
this.progressBar.style.width
|
|
4704
|
+
this.progressBar.style.setProperty("transition", "none");
|
|
4705
|
+
this.progressBar.style.setProperty("width", "0%");
|
|
4686
4706
|
}
|
|
4687
4707
|
}
|
|
4688
4708
|
/**
|
|
@@ -4759,8 +4779,8 @@ class VideoControlsUI {
|
|
|
4759
4779
|
updateProgressImmediate(currentTime, duration) {
|
|
4760
4780
|
if (!this.progressBar || duration <= 0) return;
|
|
4761
4781
|
const percent = currentTime / duration * 100;
|
|
4762
|
-
this.progressBar.style.transition
|
|
4763
|
-
this.progressBar.style.width
|
|
4782
|
+
this.progressBar.style.setProperty("transition", "none");
|
|
4783
|
+
this.progressBar.style.setProperty("width", `${percent}%`);
|
|
4764
4784
|
}
|
|
4765
4785
|
/**
|
|
4766
4786
|
* Updates the progress bar based on current playback position
|
|
@@ -4771,15 +4791,15 @@ class VideoControlsUI {
|
|
|
4771
4791
|
const duration = this.videoElement.duration || 0;
|
|
4772
4792
|
if (duration > 0) {
|
|
4773
4793
|
const percent = currentTime / duration * 100;
|
|
4774
|
-
const wasTransitioning = this.progressBar.style.transition !== "none";
|
|
4794
|
+
const wasTransitioning = this.progressBar.style.getPropertyValue("transition") !== "none";
|
|
4775
4795
|
const timeSinceLastUpdate = Date.now() - this.lastTimeupdateEvent;
|
|
4776
|
-
this.progressBar.style.transition
|
|
4777
|
-
this.progressBar.style.width
|
|
4796
|
+
this.progressBar.style.setProperty("transition", "none");
|
|
4797
|
+
this.progressBar.style.setProperty("width", `${percent}%`);
|
|
4778
4798
|
void this.progressBar.offsetWidth;
|
|
4779
4799
|
if (this.videoElement.ended) {
|
|
4780
|
-
this.progressBar.style.transition
|
|
4800
|
+
this.progressBar.style.setProperty("transition", "width 0.2s ease-out");
|
|
4781
4801
|
} else if (!this.videoElement.paused && !this.videoElement.seeking && wasTransitioning && timeSinceLastUpdate < 500) {
|
|
4782
|
-
this.progressBar.style.transition
|
|
4802
|
+
this.progressBar.style.setProperty("transition", "width 0.1s linear");
|
|
4783
4803
|
}
|
|
4784
4804
|
}
|
|
4785
4805
|
}
|
|
@@ -4856,16 +4876,16 @@ class VideoControlsUI {
|
|
|
4856
4876
|
const playerElement = this.controlsElement.closest(".sf-player");
|
|
4857
4877
|
const isMinimized = playerElement == null ? void 0 : playerElement.classList.contains("sf-player--minimized");
|
|
4858
4878
|
if (!isMinimized) {
|
|
4859
|
-
this.controlsElement.
|
|
4879
|
+
this.controlsElement.classList.remove("sf-hidden");
|
|
4860
4880
|
} else {
|
|
4861
|
-
this.controlsElement.
|
|
4881
|
+
this.controlsElement.classList.remove("sf-hidden");
|
|
4862
4882
|
}
|
|
4863
4883
|
}
|
|
4864
4884
|
if (this.progressBar) {
|
|
4865
|
-
this.progressBar.style.transition
|
|
4866
|
-
this.progressBar.style.width
|
|
4885
|
+
this.progressBar.style.setProperty("transition", "none");
|
|
4886
|
+
this.progressBar.style.setProperty("width", "0%");
|
|
4867
4887
|
void this.progressBar.offsetWidth;
|
|
4868
|
-
this.progressBar.style.transition
|
|
4888
|
+
this.progressBar.style.setProperty("transition", "width 0.1s linear");
|
|
4869
4889
|
}
|
|
4870
4890
|
}
|
|
4871
4891
|
/**
|
|
@@ -4873,7 +4893,7 @@ class VideoControlsUI {
|
|
|
4873
4893
|
*/
|
|
4874
4894
|
hideProgressBar() {
|
|
4875
4895
|
if (this.controlsElement) {
|
|
4876
|
-
this.controlsElement.
|
|
4896
|
+
this.controlsElement.classList.add("sf-hidden");
|
|
4877
4897
|
}
|
|
4878
4898
|
}
|
|
4879
4899
|
/**
|
|
@@ -4881,7 +4901,7 @@ class VideoControlsUI {
|
|
|
4881
4901
|
*/
|
|
4882
4902
|
showMuteButton() {
|
|
4883
4903
|
if (this.muteButton) {
|
|
4884
|
-
this.muteButton.
|
|
4904
|
+
this.muteButton.classList.remove("sf-hidden");
|
|
4885
4905
|
}
|
|
4886
4906
|
}
|
|
4887
4907
|
/**
|
|
@@ -4889,7 +4909,7 @@ class VideoControlsUI {
|
|
|
4889
4909
|
*/
|
|
4890
4910
|
hideMuteButton() {
|
|
4891
4911
|
if (this.muteButton) {
|
|
4892
|
-
this.muteButton.
|
|
4912
|
+
this.muteButton.classList.add("sf-hidden");
|
|
4893
4913
|
}
|
|
4894
4914
|
}
|
|
4895
4915
|
/**
|
|
@@ -4942,8 +4962,7 @@ class VideoManager {
|
|
|
4942
4962
|
this.controls.updateProgressImmediate(activeVideo.duration, activeVideo.duration);
|
|
4943
4963
|
}
|
|
4944
4964
|
if (activeVideo) {
|
|
4945
|
-
activeVideo.
|
|
4946
|
-
activeVideo.style.transition = "filter 0.3s ease-out";
|
|
4965
|
+
activeVideo.classList.add("sf-video-container__video--blurred");
|
|
4947
4966
|
}
|
|
4948
4967
|
if (this.completionPolicy === "auto") {
|
|
4949
4968
|
this.handleAutoVideoEnded();
|
|
@@ -5016,9 +5035,8 @@ class VideoManager {
|
|
|
5016
5035
|
this.deviceHandler.configureVideoElement(this.currentVideo);
|
|
5017
5036
|
this.container.appendChild(this.currentVideo);
|
|
5018
5037
|
this.nextVideo = document.createElement("video");
|
|
5019
|
-
this.nextVideo.className = "sf-video-container__video sf-video-container__video--next";
|
|
5038
|
+
this.nextVideo.className = "sf-video-container__video sf-video-container__video--next sf-hidden";
|
|
5020
5039
|
this.deviceHandler.configureVideoElement(this.nextVideo);
|
|
5021
|
-
this.nextVideo.style.display = "none";
|
|
5022
5040
|
this.container.appendChild(this.nextVideo);
|
|
5023
5041
|
const store = useSaltfishStore.getState();
|
|
5024
5042
|
if (store.isMuted) {
|
|
@@ -5077,8 +5095,8 @@ class VideoManager {
|
|
|
5077
5095
|
activeVideo.pause();
|
|
5078
5096
|
const store = useSaltfishStore.getState();
|
|
5079
5097
|
inactiveVideo.muted = store.isMuted;
|
|
5080
|
-
activeVideo.
|
|
5081
|
-
inactiveVideo.
|
|
5098
|
+
activeVideo.classList.add("sf-hidden");
|
|
5099
|
+
inactiveVideo.classList.remove("sf-hidden");
|
|
5082
5100
|
this.activeVideoIndex = this.activeVideoIndex === 0 ? 1 : 0;
|
|
5083
5101
|
this.currentVideoUrl = this.nextVideoUrl;
|
|
5084
5102
|
this.nextVideoUrl = "";
|
|
@@ -5269,10 +5287,7 @@ class VideoManager {
|
|
|
5269
5287
|
console.error("VideoManager: No active video element found");
|
|
5270
5288
|
return;
|
|
5271
5289
|
}
|
|
5272
|
-
|
|
5273
|
-
activeVideo.style.filter = "";
|
|
5274
|
-
activeVideo.style.transition = "";
|
|
5275
|
-
}
|
|
5290
|
+
activeVideo.classList.remove("sf-video-container__video--blurred");
|
|
5276
5291
|
if (activeVideo.ended) {
|
|
5277
5292
|
activeVideo.currentTime = 0;
|
|
5278
5293
|
}
|
|
@@ -5603,7 +5618,7 @@ class VideoManager {
|
|
|
5603
5618
|
return;
|
|
5604
5619
|
}
|
|
5605
5620
|
if (posterUrl) {
|
|
5606
|
-
this.container.style.
|
|
5621
|
+
this.container.style.setProperty("--sf-audio-poster-url", `url('${posterUrl}')`);
|
|
5607
5622
|
this.container.classList.add("sf-video-container--audio-fallback");
|
|
5608
5623
|
}
|
|
5609
5624
|
if (!this.audioFallbackOverlay) {
|
|
@@ -5631,7 +5646,7 @@ class VideoManager {
|
|
|
5631
5646
|
if (!this.container) {
|
|
5632
5647
|
return;
|
|
5633
5648
|
}
|
|
5634
|
-
this.container.style.
|
|
5649
|
+
this.container.style.removeProperty("--sf-audio-poster-url");
|
|
5635
5650
|
this.container.classList.remove("sf-video-container--audio-fallback");
|
|
5636
5651
|
if (this.audioFallbackOverlay && this.audioFallbackOverlay.parentNode) {
|
|
5637
5652
|
this.audioFallbackOverlay.parentNode.removeChild(this.audioFallbackOverlay);
|
|
@@ -6054,42 +6069,92 @@ class CursorManager {
|
|
|
6054
6069
|
* Creates the virtual cursor element
|
|
6055
6070
|
*/
|
|
6056
6071
|
create() {
|
|
6072
|
+
this.injectCursorStyles();
|
|
6057
6073
|
this.cursor = document.createElement("div");
|
|
6058
|
-
this.cursor.
|
|
6059
|
-
this.cursor.style.top = "0";
|
|
6060
|
-
this.cursor.style.left = "0";
|
|
6061
|
-
this.cursor.style.width = "36px";
|
|
6062
|
-
this.cursor.style.height = "36px";
|
|
6063
|
-
this.cursor.style.zIndex = "9999999";
|
|
6064
|
-
this.cursor.style.pointerEvents = "none";
|
|
6065
|
-
this.cursor.style.display = "none";
|
|
6066
|
-
this.cursor.style.willChange = "transform";
|
|
6074
|
+
this.cursor.className = "sf-cursor";
|
|
6067
6075
|
this.cursor.innerHTML = `
|
|
6068
6076
|
<svg xmlns="http://www.w3.org/2000/svg" width="36" height="36" viewBox="0 0 24 24" fill="none" stroke="#ff7614" stroke-width="2">
|
|
6069
6077
|
<path d="M3 3L10.5 21L13.5 13.5L21 10.5L3 3Z" fill="#ff7614" />
|
|
6070
6078
|
</svg>
|
|
6071
6079
|
`;
|
|
6072
6080
|
this.selectionElement = document.createElement("div");
|
|
6073
|
-
this.selectionElement.
|
|
6074
|
-
this.selectionElement.style.pointerEvents = "none";
|
|
6075
|
-
this.selectionElement.style.display = "none";
|
|
6076
|
-
this.selectionElement.style.zIndex = "9999998";
|
|
6081
|
+
this.selectionElement.className = "sf-selection";
|
|
6077
6082
|
document.body.appendChild(this.cursor);
|
|
6078
6083
|
document.body.appendChild(this.selectionElement);
|
|
6079
6084
|
this.flashlightOverlay = document.createElement("div");
|
|
6080
|
-
this.flashlightOverlay.
|
|
6081
|
-
this.flashlightOverlay.style.top = "0";
|
|
6082
|
-
this.flashlightOverlay.style.left = "0";
|
|
6083
|
-
this.flashlightOverlay.style.width = "100vw";
|
|
6084
|
-
this.flashlightOverlay.style.height = "100vh";
|
|
6085
|
-
this.flashlightOverlay.style.pointerEvents = "none";
|
|
6086
|
-
this.flashlightOverlay.style.zIndex = "999997";
|
|
6087
|
-
this.flashlightOverlay.style.display = "none";
|
|
6088
|
-
this.flashlightOverlay.style.background = "radial-gradient(circle 150px at 50% 50%, transparent 0%, rgba(0, 0, 0, 0.4) 100%)";
|
|
6085
|
+
this.flashlightOverlay.className = "sf-flashlight-overlay";
|
|
6089
6086
|
document.body.appendChild(this.flashlightOverlay);
|
|
6090
6087
|
this.boundScrollHandler = this.handleScroll.bind(this);
|
|
6091
6088
|
window.addEventListener("scroll", this.boundScrollHandler, { passive: true });
|
|
6092
6089
|
}
|
|
6090
|
+
/**
|
|
6091
|
+
* Injects cursor styles into the main document for CSP compliance
|
|
6092
|
+
* Uses adoptedStyleSheets API when available, falls back to <style> element
|
|
6093
|
+
*/
|
|
6094
|
+
injectCursorStyles() {
|
|
6095
|
+
const cursorStyles = `
|
|
6096
|
+
.sf-cursor {
|
|
6097
|
+
position: fixed;
|
|
6098
|
+
top: 0;
|
|
6099
|
+
left: 0;
|
|
6100
|
+
width: 36px;
|
|
6101
|
+
height: 36px;
|
|
6102
|
+
z-index: 9999999;
|
|
6103
|
+
pointer-events: none;
|
|
6104
|
+
display: none;
|
|
6105
|
+
will-change: transform;
|
|
6106
|
+
transform: var(--sf-cursor-transform, translate(0, 0));
|
|
6107
|
+
opacity: var(--sf-cursor-opacity, 1);
|
|
6108
|
+
}
|
|
6109
|
+
|
|
6110
|
+
.sf-cursor--visible {
|
|
6111
|
+
display: block;
|
|
6112
|
+
}
|
|
6113
|
+
|
|
6114
|
+
.sf-selection {
|
|
6115
|
+
position: fixed;
|
|
6116
|
+
pointer-events: none;
|
|
6117
|
+
display: none;
|
|
6118
|
+
z-index: 9999998;
|
|
6119
|
+
border: 2px solid #ff7614;
|
|
6120
|
+
background: rgba(255, 118, 20, 0.1);
|
|
6121
|
+
left: var(--sf-selection-left, 0);
|
|
6122
|
+
top: var(--sf-selection-top, 0);
|
|
6123
|
+
width: var(--sf-selection-width, 0);
|
|
6124
|
+
height: var(--sf-selection-height, 0);
|
|
6125
|
+
}
|
|
6126
|
+
|
|
6127
|
+
.sf-selection--visible {
|
|
6128
|
+
display: block;
|
|
6129
|
+
}
|
|
6130
|
+
|
|
6131
|
+
.sf-flashlight-overlay {
|
|
6132
|
+
position: fixed;
|
|
6133
|
+
top: 0;
|
|
6134
|
+
left: 0;
|
|
6135
|
+
width: 100vw;
|
|
6136
|
+
height: 100vh;
|
|
6137
|
+
pointer-events: none;
|
|
6138
|
+
z-index: 9999997;
|
|
6139
|
+
display: none;
|
|
6140
|
+
background: var(--sf-flashlight-bg, radial-gradient(circle 150px at 50% 50%, transparent 0%, rgba(0, 0, 0, 0.4) 100%));
|
|
6141
|
+
clip-path: var(--sf-flashlight-clip, none);
|
|
6142
|
+
}
|
|
6143
|
+
|
|
6144
|
+
.sf-flashlight-overlay--visible {
|
|
6145
|
+
display: block;
|
|
6146
|
+
}
|
|
6147
|
+
`;
|
|
6148
|
+
try {
|
|
6149
|
+
const sheet = new CSSStyleSheet();
|
|
6150
|
+
sheet.replaceSync(cursorStyles);
|
|
6151
|
+
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
|
|
6152
|
+
} catch (error2) {
|
|
6153
|
+
const styleElement = document.createElement("style");
|
|
6154
|
+
styleElement.textContent = cursorStyles;
|
|
6155
|
+
document.head.appendChild(styleElement);
|
|
6156
|
+
}
|
|
6157
|
+
}
|
|
6093
6158
|
/**
|
|
6094
6159
|
* Handles scrolling to keep the cursor positioned on the target element
|
|
6095
6160
|
* Uses requestAnimationFrame for smooth 60fps updates
|
|
@@ -6186,12 +6251,12 @@ class CursorManager {
|
|
|
6186
6251
|
this.lastCursorX = x;
|
|
6187
6252
|
this.lastCursorY = y;
|
|
6188
6253
|
if (this.cursor) {
|
|
6189
|
-
this.cursor.
|
|
6190
|
-
this.cursor.style.transform
|
|
6254
|
+
this.cursor.classList.add("sf-cursor--visible");
|
|
6255
|
+
this.cursor.style.setProperty("--sf-cursor-transform", `translate(${x}px, ${y}px) translate(-50%, -50%)`);
|
|
6191
6256
|
}
|
|
6192
6257
|
if (this.flashlightOverlay) {
|
|
6193
|
-
this.flashlightOverlay.
|
|
6194
|
-
this.flashlightOverlay.style.
|
|
6258
|
+
this.flashlightOverlay.classList.add("sf-flashlight-overlay--visible");
|
|
6259
|
+
this.flashlightOverlay.style.setProperty("--sf-flashlight-bg", `radial-gradient(circle 150px at ${x}px ${y}px, transparent 0%, rgba(0, 0, 0, 0.4) 100%)`);
|
|
6195
6260
|
}
|
|
6196
6261
|
}
|
|
6197
6262
|
/**
|
|
@@ -6199,13 +6264,13 @@ class CursorManager {
|
|
|
6199
6264
|
*/
|
|
6200
6265
|
hideCursorElements() {
|
|
6201
6266
|
if (this.cursor) {
|
|
6202
|
-
this.cursor.
|
|
6267
|
+
this.cursor.classList.remove("sf-cursor--visible");
|
|
6203
6268
|
}
|
|
6204
6269
|
if (this.selectionElement) {
|
|
6205
|
-
this.selectionElement.
|
|
6270
|
+
this.selectionElement.classList.remove("sf-selection--visible");
|
|
6206
6271
|
}
|
|
6207
6272
|
if (this.flashlightOverlay) {
|
|
6208
|
-
this.flashlightOverlay.
|
|
6273
|
+
this.flashlightOverlay.classList.remove("sf-flashlight-overlay--visible");
|
|
6209
6274
|
this.resetFlashlightOverlay();
|
|
6210
6275
|
}
|
|
6211
6276
|
}
|
|
@@ -6216,10 +6281,10 @@ class CursorManager {
|
|
|
6216
6281
|
if (!this.flashlightOverlay) {
|
|
6217
6282
|
return;
|
|
6218
6283
|
}
|
|
6219
|
-
this.flashlightOverlay.style.
|
|
6284
|
+
this.flashlightOverlay.style.setProperty("--sf-flashlight-clip", "none");
|
|
6220
6285
|
const x = this.lastCursorX;
|
|
6221
6286
|
const y = this.lastCursorY;
|
|
6222
|
-
this.flashlightOverlay.style.
|
|
6287
|
+
this.flashlightOverlay.style.setProperty("--sf-flashlight-bg", `radial-gradient(circle 150px at ${x}px ${y}px, transparent 0%, rgba(0, 0, 0, 0.4) 100%)`);
|
|
6223
6288
|
}
|
|
6224
6289
|
/**
|
|
6225
6290
|
* Animates the cursor along a path
|
|
@@ -6235,7 +6300,7 @@ class CursorManager {
|
|
|
6235
6300
|
this.isSelectionMode = false;
|
|
6236
6301
|
this.resetFlashlightOverlay();
|
|
6237
6302
|
if (this.selectionElement) {
|
|
6238
|
-
this.selectionElement.
|
|
6303
|
+
this.selectionElement.classList.remove("sf-selection--visible");
|
|
6239
6304
|
}
|
|
6240
6305
|
if (!(animation == null ? void 0 : animation.targetSelector)) {
|
|
6241
6306
|
console.warn("CursorManager: No targetSelector provided in animation");
|
|
@@ -6277,7 +6342,7 @@ class CursorManager {
|
|
|
6277
6342
|
this.targetX = targetRect.left + targetRect.width / 2 + this.POINTER_HORIZONTAL_OFFSET;
|
|
6278
6343
|
this.targetY = targetRect.top + targetRect.height / 2 + this.POINTER_VERTICAL_OFFSET;
|
|
6279
6344
|
if (this.selectionElement) {
|
|
6280
|
-
this.selectionElement.
|
|
6345
|
+
this.selectionElement.classList.remove("sf-selection--visible");
|
|
6281
6346
|
}
|
|
6282
6347
|
}
|
|
6283
6348
|
if (this.targetX !== null && this.targetY !== null && this.startX !== null && this.startY !== null) {
|
|
@@ -6326,7 +6391,7 @@ class CursorManager {
|
|
|
6326
6391
|
this.selectionElement.style.setProperty("--sf-selection-border-radius", animation.selectionStyles.borderRadius);
|
|
6327
6392
|
}
|
|
6328
6393
|
}
|
|
6329
|
-
this.selectionElement.
|
|
6394
|
+
this.selectionElement.classList.remove("sf-selection--visible");
|
|
6330
6395
|
}
|
|
6331
6396
|
this.calculateControlPoint();
|
|
6332
6397
|
this.currentAnimation = { ...animation };
|
|
@@ -6368,11 +6433,11 @@ class CursorManager {
|
|
|
6368
6433
|
this.dragStartY,
|
|
6369
6434
|
currentY - this.SELECTION_VERTICAL_OFFSET
|
|
6370
6435
|
));
|
|
6371
|
-
this.selectionElement.style.left
|
|
6372
|
-
this.selectionElement.style.top
|
|
6373
|
-
this.selectionElement.style.width
|
|
6374
|
-
this.selectionElement.style.height
|
|
6375
|
-
this.selectionElement.
|
|
6436
|
+
this.selectionElement.style.setProperty("--sf-selection-left", `${left}px`);
|
|
6437
|
+
this.selectionElement.style.setProperty("--sf-selection-top", `${top}px`);
|
|
6438
|
+
this.selectionElement.style.setProperty("--sf-selection-width", `${width}px`);
|
|
6439
|
+
this.selectionElement.style.setProperty("--sf-selection-height", `${height}px`);
|
|
6440
|
+
this.selectionElement.classList.add("sf-selection--visible");
|
|
6376
6441
|
this.updateFlashlightWithCutout(left, top, width, height);
|
|
6377
6442
|
}
|
|
6378
6443
|
/**
|
|
@@ -6420,15 +6485,15 @@ class CursorManager {
|
|
|
6420
6485
|
if (this.cursor) {
|
|
6421
6486
|
const x = this.lastCursorX;
|
|
6422
6487
|
const y = this.lastCursorY;
|
|
6423
|
-
this.cursor.style.transform
|
|
6424
|
-
this.cursor.style.opacity
|
|
6488
|
+
this.cursor.style.setProperty("--sf-cursor-transform", `translate(${x}px, ${y}px) translate(-50%, -50%) scale(0.9)`);
|
|
6489
|
+
this.cursor.style.setProperty("--sf-cursor-opacity", "0.9");
|
|
6425
6490
|
}
|
|
6426
6491
|
if (this.selectionElement) {
|
|
6427
|
-
this.selectionElement.style.left
|
|
6428
|
-
this.selectionElement.style.top
|
|
6429
|
-
this.selectionElement.style.width
|
|
6430
|
-
this.selectionElement.style.height
|
|
6431
|
-
this.selectionElement.
|
|
6492
|
+
this.selectionElement.style.setProperty("--sf-selection-left", `${this.dragStartX}px`);
|
|
6493
|
+
this.selectionElement.style.setProperty("--sf-selection-top", `${this.dragStartY}px`);
|
|
6494
|
+
this.selectionElement.style.setProperty("--sf-selection-width", "0px");
|
|
6495
|
+
this.selectionElement.style.setProperty("--sf-selection-height", "0px");
|
|
6496
|
+
this.selectionElement.classList.add("sf-selection--visible");
|
|
6432
6497
|
}
|
|
6433
6498
|
}
|
|
6434
6499
|
/**
|
|
@@ -6439,8 +6504,8 @@ class CursorManager {
|
|
|
6439
6504
|
if (this.cursor) {
|
|
6440
6505
|
const x = this.lastCursorX;
|
|
6441
6506
|
const y = this.lastCursorY;
|
|
6442
|
-
this.cursor.style.transform
|
|
6443
|
-
this.cursor.style.opacity
|
|
6507
|
+
this.cursor.style.setProperty("--sf-cursor-transform", `translate(${x}px, ${y}px) translate(-50%, -50%)`);
|
|
6508
|
+
this.cursor.style.setProperty("--sf-cursor-opacity", "1");
|
|
6444
6509
|
}
|
|
6445
6510
|
if (this.animationFrameId !== null) {
|
|
6446
6511
|
cancelAnimationFrame(this.animationFrameId);
|
|
@@ -6603,10 +6668,10 @@ class CursorManager {
|
|
|
6603
6668
|
0% ${top}px /* Close cutout path */
|
|
6604
6669
|
)
|
|
6605
6670
|
`;
|
|
6606
|
-
this.flashlightOverlay.style.
|
|
6671
|
+
this.flashlightOverlay.style.setProperty("--sf-flashlight-clip", clipPath);
|
|
6607
6672
|
const x = this.lastCursorX;
|
|
6608
6673
|
const y = this.lastCursorY;
|
|
6609
|
-
this.flashlightOverlay.style.
|
|
6674
|
+
this.flashlightOverlay.style.setProperty("--sf-flashlight-bg", `radial-gradient(circle 150px at ${x}px ${y}px, transparent 0%, rgba(0, 0, 0, 0.4) 100%)`);
|
|
6610
6675
|
}
|
|
6611
6676
|
/**
|
|
6612
6677
|
* Calculates a control point for curved cursor movement
|
|
@@ -6691,16 +6756,16 @@ class CursorManager {
|
|
|
6691
6756
|
if (this.cursor) {
|
|
6692
6757
|
const x = this.lastCursorX;
|
|
6693
6758
|
const y = this.lastCursorY;
|
|
6694
|
-
this.cursor.style.transform
|
|
6695
|
-
this.cursor.style.opacity
|
|
6759
|
+
this.cursor.style.setProperty("--sf-cursor-transform", `translate(${x}px, ${y}px) translate(-50%, -50%) scale(0.8)`);
|
|
6760
|
+
this.cursor.style.setProperty("--sf-cursor-opacity", "0.8");
|
|
6696
6761
|
setTimeout(() => {
|
|
6697
6762
|
if (this.cursor) {
|
|
6698
6763
|
if (!this.canShowCursor()) {
|
|
6699
6764
|
this.hideCursorElements();
|
|
6700
6765
|
return;
|
|
6701
6766
|
}
|
|
6702
|
-
this.cursor.style.transform
|
|
6703
|
-
this.cursor.style.opacity
|
|
6767
|
+
this.cursor.style.setProperty("--sf-cursor-transform", `translate(${x}px, ${y}px) translate(-50%, -50%)`);
|
|
6768
|
+
this.cursor.style.setProperty("--sf-cursor-opacity", "1");
|
|
6704
6769
|
}
|
|
6705
6770
|
}, 300);
|
|
6706
6771
|
}
|
|
@@ -6722,12 +6787,12 @@ class CursorManager {
|
|
|
6722
6787
|
if (this.cursor) {
|
|
6723
6788
|
const x = this.lastCursorX;
|
|
6724
6789
|
const y = this.lastCursorY;
|
|
6725
|
-
this.cursor.style.transform
|
|
6726
|
-
this.cursor.style.opacity
|
|
6790
|
+
this.cursor.style.setProperty("--sf-cursor-transform", `translate(${x}px, ${y}px) translate(-50%, -50%)`);
|
|
6791
|
+
this.cursor.style.setProperty("--sf-cursor-opacity", "1");
|
|
6727
6792
|
}
|
|
6728
6793
|
this.resetFlashlightOverlay();
|
|
6729
6794
|
if (this.selectionElement) {
|
|
6730
|
-
this.selectionElement.
|
|
6795
|
+
this.selectionElement.classList.remove("sf-selection--visible");
|
|
6731
6796
|
}
|
|
6732
6797
|
}
|
|
6733
6798
|
/**
|
|
@@ -6755,11 +6820,11 @@ class CursorManager {
|
|
|
6755
6820
|
this.isFirstAnimation = true;
|
|
6756
6821
|
this.shouldShowCursor = false;
|
|
6757
6822
|
if (this.cursor) {
|
|
6758
|
-
this.cursor.
|
|
6823
|
+
this.cursor.classList.remove("sf-cursor--visible");
|
|
6759
6824
|
}
|
|
6760
6825
|
this.isSelectionMode = false;
|
|
6761
6826
|
if (this.selectionElement) {
|
|
6762
|
-
this.selectionElement.
|
|
6827
|
+
this.selectionElement.classList.remove("sf-selection--visible");
|
|
6763
6828
|
}
|
|
6764
6829
|
this.dragStartX = null;
|
|
6765
6830
|
this.dragStartY = null;
|
|
@@ -6917,7 +6982,7 @@ class InteractionManager {
|
|
|
6917
6982
|
}
|
|
6918
6983
|
const store = useSaltfishStore.getState();
|
|
6919
6984
|
if (store.isMinimized) {
|
|
6920
|
-
this.buttonContainer.
|
|
6985
|
+
this.buttonContainer.classList.add("sf-hidden");
|
|
6921
6986
|
}
|
|
6922
6987
|
}
|
|
6923
6988
|
/**
|
|
@@ -6996,15 +7061,15 @@ class InteractionManager {
|
|
|
6996
7061
|
}
|
|
6997
7062
|
const store = useSaltfishStore.getState();
|
|
6998
7063
|
if (store.isMinimized) {
|
|
6999
|
-
this.buttonContainer.
|
|
7064
|
+
this.buttonContainer.classList.add("sf-hidden");
|
|
7000
7065
|
if (this.scrollIndicator) {
|
|
7001
|
-
this.scrollIndicator.
|
|
7066
|
+
this.scrollIndicator.classList.add("sf-hidden");
|
|
7002
7067
|
}
|
|
7003
7068
|
return;
|
|
7004
7069
|
} else {
|
|
7005
|
-
this.buttonContainer.
|
|
7070
|
+
this.buttonContainer.classList.remove("sf-hidden");
|
|
7006
7071
|
if (this.scrollIndicator) {
|
|
7007
|
-
this.scrollIndicator.
|
|
7072
|
+
this.scrollIndicator.classList.remove("sf-hidden");
|
|
7008
7073
|
}
|
|
7009
7074
|
}
|
|
7010
7075
|
this.buttonContainer.className = "sf-choice-buttons-container";
|
|
@@ -9501,9 +9566,9 @@ class MinimizeButton {
|
|
|
9501
9566
|
}
|
|
9502
9567
|
updateVisibility(isMinimized) {
|
|
9503
9568
|
if (isMinimized) {
|
|
9504
|
-
this.button.
|
|
9569
|
+
this.button.classList.add("sf-hidden");
|
|
9505
9570
|
} else {
|
|
9506
|
-
this.button.
|
|
9571
|
+
this.button.classList.remove("sf-hidden");
|
|
9507
9572
|
}
|
|
9508
9573
|
}
|
|
9509
9574
|
destroy() {
|
|
@@ -9595,9 +9660,9 @@ class ExitButton {
|
|
|
9595
9660
|
}
|
|
9596
9661
|
updateVisibility(isMinimized) {
|
|
9597
9662
|
if (isMinimized) {
|
|
9598
|
-
this.button.
|
|
9663
|
+
this.button.classList.remove("sf-hidden");
|
|
9599
9664
|
} else {
|
|
9600
|
-
this.button.
|
|
9665
|
+
this.button.classList.add("sf-hidden");
|
|
9601
9666
|
}
|
|
9602
9667
|
}
|
|
9603
9668
|
destroy() {
|
|
@@ -9621,7 +9686,7 @@ class ErrorDisplay {
|
|
|
9621
9686
|
createErrorDisplay() {
|
|
9622
9687
|
this.errorOverlay = document.createElement("div");
|
|
9623
9688
|
this.errorOverlay.className = CSS_CLASSES.ERROR_DISPLAY;
|
|
9624
|
-
this.errorOverlay.
|
|
9689
|
+
this.errorOverlay.classList.add("sf-hidden");
|
|
9625
9690
|
const errorContent = document.createElement("div");
|
|
9626
9691
|
errorContent.className = CSS_CLASSES.ERROR_DISPLAY_CONTENT;
|
|
9627
9692
|
const errorMessage = document.createElement("p");
|
|
@@ -9638,7 +9703,7 @@ class ErrorDisplay {
|
|
|
9638
9703
|
if (newOptions) {
|
|
9639
9704
|
this.updateOptions(newOptions);
|
|
9640
9705
|
}
|
|
9641
|
-
this.errorOverlay.
|
|
9706
|
+
this.errorOverlay.classList.remove("sf-hidden");
|
|
9642
9707
|
this.isVisible = true;
|
|
9643
9708
|
requestAnimationFrame(() => {
|
|
9644
9709
|
this.errorOverlay.classList.add(CSS_CLASSES.ERROR_DISPLAY_VISIBLE);
|
|
@@ -9653,7 +9718,7 @@ class ErrorDisplay {
|
|
|
9653
9718
|
}
|
|
9654
9719
|
this.errorOverlay.classList.remove(CSS_CLASSES.ERROR_DISPLAY_VISIBLE);
|
|
9655
9720
|
setTimeout(() => {
|
|
9656
|
-
this.errorOverlay.
|
|
9721
|
+
this.errorOverlay.classList.add("sf-hidden");
|
|
9657
9722
|
this.isVisible = false;
|
|
9658
9723
|
}, 300);
|
|
9659
9724
|
}
|
|
@@ -9718,7 +9783,7 @@ class LoadingSpinner {
|
|
|
9718
9783
|
*/
|
|
9719
9784
|
show() {
|
|
9720
9785
|
if (this.spinnerElement) {
|
|
9721
|
-
this.spinnerElement.
|
|
9786
|
+
this.spinnerElement.classList.remove("sf-hidden");
|
|
9722
9787
|
return;
|
|
9723
9788
|
}
|
|
9724
9789
|
this.spinnerElement = document.createElement("div");
|
|
@@ -9763,7 +9828,7 @@ class LoadingSpinner {
|
|
|
9763
9828
|
*/
|
|
9764
9829
|
hide() {
|
|
9765
9830
|
if (this.spinnerElement) {
|
|
9766
|
-
this.spinnerElement.
|
|
9831
|
+
this.spinnerElement.classList.add("sf-hidden");
|
|
9767
9832
|
}
|
|
9768
9833
|
}
|
|
9769
9834
|
/**
|
|
@@ -9885,9 +9950,6 @@ class UIManager {
|
|
|
9885
9950
|
console.warn(`UIManager: Invalid position "${positionToUse}", defaulting to bottom-right`);
|
|
9886
9951
|
positionToUse = "bottom-right";
|
|
9887
9952
|
}
|
|
9888
|
-
this.playerRoot.style.left = "";
|
|
9889
|
-
this.playerRoot.style.top = "";
|
|
9890
|
-
this.playerRoot.style.transform = "";
|
|
9891
9953
|
this.playerRoot.classList.remove("sf-player-root--bottom-left", "sf-player-root--bottom-right");
|
|
9892
9954
|
if (positionToUse === "bottom-left") {
|
|
9893
9955
|
this.playerRoot.classList.add("sf-player-root--bottom-left");
|
|
@@ -10117,7 +10179,7 @@ class UIManager {
|
|
|
10117
10179
|
*/
|
|
10118
10180
|
updatePlayPauseButton(state) {
|
|
10119
10181
|
if (this.playButton) {
|
|
10120
|
-
this.playButton.
|
|
10182
|
+
this.playButton.classList.add("sf-hidden");
|
|
10121
10183
|
}
|
|
10122
10184
|
if (!this.centerPlayButton && this.playerElement) {
|
|
10123
10185
|
this.centerPlayButton = this.playerElement.querySelector(".sf-player__center-play-button");
|
|
@@ -10129,12 +10191,14 @@ class UIManager {
|
|
|
10129
10191
|
return;
|
|
10130
10192
|
}
|
|
10131
10193
|
if (state === "playing" || state === "completed") {
|
|
10132
|
-
this.centerPlayButton.
|
|
10194
|
+
this.centerPlayButton.classList.remove("sf-player__center-play-button--visible");
|
|
10195
|
+
this.centerPlayButton.classList.remove("sf-player__center-play-button--prominent");
|
|
10133
10196
|
} else {
|
|
10134
|
-
this.centerPlayButton.
|
|
10197
|
+
this.centerPlayButton.classList.add("sf-player__center-play-button--visible");
|
|
10135
10198
|
if (state === "autoplayBlocked" || state === "idleMode") {
|
|
10136
|
-
this.centerPlayButton.
|
|
10137
|
-
|
|
10199
|
+
this.centerPlayButton.classList.add("sf-player__center-play-button--prominent");
|
|
10200
|
+
} else {
|
|
10201
|
+
this.centerPlayButton.classList.remove("sf-player__center-play-button--prominent");
|
|
10138
10202
|
}
|
|
10139
10203
|
}
|
|
10140
10204
|
}
|
|
@@ -10221,8 +10285,7 @@ class UIManager {
|
|
|
10221
10285
|
*/
|
|
10222
10286
|
enablePlayButtonProminent() {
|
|
10223
10287
|
if (this.centerPlayButton) {
|
|
10224
|
-
this.centerPlayButton.
|
|
10225
|
-
this.centerPlayButton.style.pointerEvents = "auto";
|
|
10288
|
+
this.centerPlayButton.classList.add("sf-player__center-play-button--prominent");
|
|
10226
10289
|
}
|
|
10227
10290
|
}
|
|
10228
10291
|
/**
|
|
@@ -10230,8 +10293,7 @@ class UIManager {
|
|
|
10230
10293
|
*/
|
|
10231
10294
|
disablePlayButtonProminent() {
|
|
10232
10295
|
if (this.centerPlayButton) {
|
|
10233
|
-
this.centerPlayButton.
|
|
10234
|
-
this.centerPlayButton.style.pointerEvents = "";
|
|
10296
|
+
this.centerPlayButton.classList.remove("sf-player__center-play-button--prominent");
|
|
10235
10297
|
}
|
|
10236
10298
|
}
|
|
10237
10299
|
/**
|
|
@@ -10614,7 +10676,7 @@ const SaltfishPlayer$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.de
|
|
|
10614
10676
|
__proto__: null,
|
|
10615
10677
|
SaltfishPlayer
|
|
10616
10678
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
10617
|
-
const version = "0.2.
|
|
10679
|
+
const version = "0.2.66";
|
|
10618
10680
|
const packageJson = {
|
|
10619
10681
|
version
|
|
10620
10682
|
};
|