mirror of
https://github.com/mediacms-io/mediacms.git
synced 2025-11-06 07:28:53 -05:00
Improve mobile UX for chapters overlay and add chapters
Enhanced the CustomChaptersOverlay component and CSS for a more responsive, touch-friendly mobile experience, including haptic feedback, scroll optimizations, and body scroll locking. Updated SubtitlesButton indicator for better alignment. Added multiple new chapters to the sample video in VideoJSPlayer.jsx for richer navigation.
This commit is contained in:
parent
ab96f33bf3
commit
8eb196bf74
@ -249,67 +249,332 @@
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* Improve touch scrolling on mobile */
|
||||
/* Mobile-first responsive design */
|
||||
@media (max-width: 767px) {
|
||||
.custom-chapters-overlay {
|
||||
background: rgba(0, 0, 0, 0.5) !important;
|
||||
}
|
||||
|
||||
.video-chapter {
|
||||
right: 4px !important;
|
||||
left: 4px !important;
|
||||
width: calc(100% - 8px) !important;
|
||||
max-width: none !important;
|
||||
height: calc(100% - 50px) !important;
|
||||
bottom: 45px !important;
|
||||
border-radius: 10px !important;
|
||||
}
|
||||
|
||||
.chapter-body {
|
||||
-webkit-overflow-scrolling: touch;
|
||||
touch-action: pan-y;
|
||||
overscroll-behavior: contain;
|
||||
height: calc(100% - 70px);
|
||||
height: calc(100% - 55px);
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
.chapter-body::-webkit-scrollbar {
|
||||
width: 0px;
|
||||
}
|
||||
|
||||
div.chapter-close button {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.video-js-root-main .video-js.video-js-rounded-corners .custom-chapters-overlay {
|
||||
border-bottom-left-radius: 12px !important;
|
||||
border-bottom-right-radius: 12px !important;
|
||||
}
|
||||
|
||||
.custom-chapters-overlay .video-chapter {
|
||||
right: 10px;
|
||||
left: auto;
|
||||
width: 100%;
|
||||
max-width: calc(300px - 20px);
|
||||
height: calc(100% - 40px);
|
||||
max-height: calc(100% - 40px);
|
||||
overflow: hidden;
|
||||
bottom: 40px;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.chapter-head {
|
||||
padding: 10px 15px;
|
||||
padding: 8px 12px;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.12);
|
||||
}
|
||||
|
||||
.chapter-close button {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 6px;
|
||||
transition: background-color 0.2s ease;
|
||||
}
|
||||
|
||||
.chapter-close button:active {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
.chapter-title h3 a {
|
||||
font-size: 15px !important;
|
||||
line-height: 20px !important;
|
||||
height: 20px !important;
|
||||
font-size: 14px !important;
|
||||
line-height: 18px !important;
|
||||
height: auto !important;
|
||||
font-weight: 600 !important;
|
||||
}
|
||||
|
||||
.chapter-title p {
|
||||
font-size: 11px !important;
|
||||
line-height: 14px !important;
|
||||
margin-top: 1px !important;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.playlist-items {
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
|
||||
}
|
||||
|
||||
.playlist-items:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.playlist-items a {
|
||||
padding: 10px 16px !important;
|
||||
min-height: 58px !important;
|
||||
padding: 10px 12px !important;
|
||||
min-height: 52px !important;
|
||||
gap: 10px !important;
|
||||
transition: background-color 0.2s ease;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.playlist-items a:active {
|
||||
background: rgba(255, 255, 255, 0.12) !important;
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
.playlist-items.selected a {
|
||||
background: rgba(255, 255, 255, 0.16) !important;
|
||||
}
|
||||
|
||||
.playlist-drag-handle {
|
||||
width: 24px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.thumbnail-meta {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.thumbnail-meta h4 {
|
||||
font-size: 13px !important;
|
||||
line-height: 18px !important;
|
||||
line-height: 17px !important;
|
||||
font-weight: 500 !important;
|
||||
margin-bottom: 3px !important;
|
||||
-webkit-line-clamp: 2;
|
||||
line-clamp: 2;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-height: 34px;
|
||||
}
|
||||
|
||||
.thumbnail-meta .meta-sub {
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.thumbnail-meta .meta-sub .meta-dynamic {
|
||||
font-size: 11px !important;
|
||||
line-height: 14px !important;
|
||||
color: #bdbdbd;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.thumbnail-action {
|
||||
display: none; /* Hide action buttons on mobile for cleaner look */
|
||||
}
|
||||
}
|
||||
|
||||
/* Extra small screens (phones in portrait) - Ultra compact */
|
||||
@media (max-width: 480px) {
|
||||
.video-chapter {
|
||||
right: 2px !important;
|
||||
left: 2px !important;
|
||||
width: calc(100% - 4px) !important;
|
||||
height: calc(100% - 40px) !important;
|
||||
bottom: 35px !important;
|
||||
border-radius: 8px !important;
|
||||
}
|
||||
|
||||
.chapter-head {
|
||||
padding: 6px 10px;
|
||||
}
|
||||
|
||||
.chapter-body {
|
||||
height: calc(100% - 45px);
|
||||
}
|
||||
|
||||
.chapter-close button {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
.chapter-title h3 a {
|
||||
font-size: 13px !important;
|
||||
line-height: 16px !important;
|
||||
}
|
||||
|
||||
.chapter-title p {
|
||||
font-size: 10px !important;
|
||||
line-height: 13px !important;
|
||||
}
|
||||
|
||||
.playlist-items a {
|
||||
padding: 8px 10px !important;
|
||||
min-height: 44px !important;
|
||||
gap: 8px !important;
|
||||
}
|
||||
|
||||
.playlist-drag-handle {
|
||||
width: 20px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.thumbnail-meta h4 {
|
||||
font-size: 12px !important;
|
||||
line-height: 15px !important;
|
||||
margin-bottom: 2px !important;
|
||||
max-height: 30px;
|
||||
}
|
||||
|
||||
.thumbnail-meta .meta-sub {
|
||||
gap: 3px;
|
||||
}
|
||||
|
||||
.thumbnail-meta .meta-sub .meta-dynamic {
|
||||
font-size: 10px !important;
|
||||
line-height: 13px !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Very small screens (< 360px) - Maximum compactness */
|
||||
@media (max-width: 360px) {
|
||||
.video-chapter {
|
||||
right: 1px !important;
|
||||
left: 1px !important;
|
||||
width: calc(100% - 2px) !important;
|
||||
height: calc(100% - 35px) !important;
|
||||
bottom: 30px !important;
|
||||
border-radius: 6px !important;
|
||||
}
|
||||
|
||||
.chapter-head {
|
||||
padding: 5px 8px;
|
||||
}
|
||||
|
||||
.chapter-body {
|
||||
height: calc(100% - 40px);
|
||||
}
|
||||
|
||||
.chapter-close button {
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
}
|
||||
|
||||
.chapter-title h3 a {
|
||||
font-size: 12px !important;
|
||||
line-height: 15px !important;
|
||||
}
|
||||
|
||||
.chapter-title p {
|
||||
font-size: 9px !important;
|
||||
line-height: 12px !important;
|
||||
}
|
||||
|
||||
.playlist-items a {
|
||||
padding: 6px 8px !important;
|
||||
min-height: 40px !important;
|
||||
gap: 6px !important;
|
||||
}
|
||||
|
||||
.playlist-drag-handle {
|
||||
width: 18px;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.thumbnail-meta h4 {
|
||||
font-size: 11px !important;
|
||||
line-height: 14px !important;
|
||||
margin-bottom: 1px !important;
|
||||
max-height: 28px;
|
||||
-webkit-line-clamp: 2;
|
||||
}
|
||||
|
||||
.thumbnail-meta .meta-sub {
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.thumbnail-meta .meta-sub .meta-dynamic {
|
||||
font-size: 9px !important;
|
||||
line-height: 12px !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Landscape orientation on mobile - Compact for limited height */
|
||||
@media (max-width: 767px) and (orientation: landscape) {
|
||||
.video-chapter {
|
||||
height: calc(100% - 30px) !important;
|
||||
bottom: 25px !important;
|
||||
max-height: 350px;
|
||||
right: 2px !important;
|
||||
left: 2px !important;
|
||||
width: calc(100% - 4px) !important;
|
||||
}
|
||||
|
||||
.chapter-body {
|
||||
height: calc(100% - 45px);
|
||||
}
|
||||
|
||||
.chapter-head {
|
||||
padding: 6px 12px;
|
||||
}
|
||||
|
||||
.chapter-close button {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
.chapter-title h3 a {
|
||||
font-size: 13px !important;
|
||||
line-height: 16px !important;
|
||||
}
|
||||
|
||||
.chapter-title p {
|
||||
font-size: 10px !important;
|
||||
line-height: 13px !important;
|
||||
}
|
||||
|
||||
.playlist-items a {
|
||||
padding: 7px 12px !important;
|
||||
min-height: 42px !important;
|
||||
gap: 8px !important;
|
||||
}
|
||||
|
||||
.thumbnail-meta h4 {
|
||||
font-size: 12px !important;
|
||||
line-height: 15px !important;
|
||||
margin-bottom: 2px !important;
|
||||
max-height: 30px;
|
||||
}
|
||||
|
||||
.thumbnail-meta .meta-sub .meta-dynamic {
|
||||
font-size: 10px !important;
|
||||
line-height: 13px !important;
|
||||
}
|
||||
|
||||
.playlist-drag-handle {
|
||||
width: 20px;
|
||||
font-size: 11px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Touch-friendly improvements for all mobile devices */
|
||||
@media (hover: none) and (pointer: coarse) {
|
||||
.playlist-items a {
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
|
||||
.chapter-close button {
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
|
||||
/* Ensure smooth scrolling on touch devices */
|
||||
.chapter-body {
|
||||
-webkit-overflow-scrolling: touch;
|
||||
scroll-behavior: smooth;
|
||||
overscroll-behavior-y: contain;
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,6 +16,10 @@ class CustomChaptersOverlay extends Component {
|
||||
this.channelName = options.channelName || '';
|
||||
this.thumbnail = options.thumbnail || '';
|
||||
this.isScrolling = false;
|
||||
this.isMobile = this.detectMobile();
|
||||
this.touchStartTime = 0;
|
||||
this.touchThreshold = 150; // ms for tap vs scroll detection
|
||||
this.isSmallScreen = window.innerWidth <= 480;
|
||||
|
||||
// Bind methods
|
||||
this.createOverlay = this.createOverlay.bind(this);
|
||||
@ -23,14 +27,60 @@ class CustomChaptersOverlay extends Component {
|
||||
this.toggleOverlay = this.toggleOverlay.bind(this);
|
||||
this.formatTime = this.formatTime.bind(this);
|
||||
this.getChapterTimeRange = this.getChapterTimeRange.bind(this);
|
||||
this.detectMobile = this.detectMobile.bind(this);
|
||||
this.handleMobileInteraction = this.handleMobileInteraction.bind(this);
|
||||
this.setupResizeListener = this.setupResizeListener.bind(this);
|
||||
this.handleResize = this.handleResize.bind(this);
|
||||
|
||||
// Initialize after player is ready
|
||||
this.player().ready(() => {
|
||||
this.createOverlay();
|
||||
this.setupChaptersButton();
|
||||
this.setupResizeListener();
|
||||
});
|
||||
}
|
||||
|
||||
detectMobile() {
|
||||
return (
|
||||
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ||
|
||||
(navigator.maxTouchPoints && navigator.maxTouchPoints > 0) ||
|
||||
window.matchMedia('(hover: none) and (pointer: coarse)').matches
|
||||
);
|
||||
}
|
||||
|
||||
handleMobileInteraction(event, chapter, index) {
|
||||
if (!this.isMobile) return;
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
// Add haptic feedback if available
|
||||
if (navigator.vibrate) {
|
||||
navigator.vibrate(50);
|
||||
}
|
||||
|
||||
// Seek to chapter and close overlay
|
||||
this.player().currentTime(chapter.startTime);
|
||||
this.overlay.style.display = 'none';
|
||||
this.updateActiveItem(index);
|
||||
|
||||
const el = this.player().el();
|
||||
if (el) el.classList.remove('chapters-open');
|
||||
}
|
||||
|
||||
setupResizeListener() {
|
||||
this.handleResize = () => {
|
||||
this.isSmallScreen = window.innerWidth <= 480;
|
||||
};
|
||||
|
||||
window.addEventListener('resize', this.handleResize);
|
||||
window.addEventListener('orientationchange', this.handleResize);
|
||||
}
|
||||
|
||||
handleResize() {
|
||||
// Update small screen detection on resize/orientation change
|
||||
this.isSmallScreen = window.innerWidth <= 480;
|
||||
}
|
||||
|
||||
formatTime(seconds) {
|
||||
const totalSec = Math.max(0, Math.floor(seconds));
|
||||
const hh = Math.floor(totalSec / 3600);
|
||||
@ -125,7 +175,25 @@ class CustomChaptersOverlay extends Component {
|
||||
-webkit-overflow-scrolling: touch;
|
||||
touch-action: pan-y;
|
||||
overscroll-behavior: contain;
|
||||
scroll-behavior: smooth;
|
||||
`;
|
||||
|
||||
// Add mobile-specific scroll optimization
|
||||
if (this.isMobile) {
|
||||
body.style.cssText += `
|
||||
scroll-snap-type: y proximity;
|
||||
overscroll-behavior-y: contain;
|
||||
`;
|
||||
|
||||
// For very small screens, add momentum scrolling optimization
|
||||
if (this.isSmallScreen) {
|
||||
body.style.cssText += `
|
||||
scroll-padding-top: 5px;
|
||||
scroll-padding-bottom: 5px;
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
container.appendChild(body);
|
||||
|
||||
const list = document.createElement('ul');
|
||||
@ -180,27 +248,23 @@ class CustomChaptersOverlay extends Component {
|
||||
</svg>`;
|
||||
action.appendChild(btn);
|
||||
|
||||
// Handle click and touch events properly
|
||||
const seekFn = (e) => {
|
||||
// Prevent default only for navigation, not scrolling
|
||||
if (e.type === 'click' || (e.type === 'touchend' && !this.isScrolling)) {
|
||||
e.preventDefault();
|
||||
this.player().currentTime(chapter.startTime);
|
||||
this.overlay.style.display = 'none';
|
||||
this.updateActiveItem(index);
|
||||
}
|
||||
};
|
||||
|
||||
// Track scrolling state for touch devices
|
||||
// Enhanced mobile touch handling
|
||||
if (this.isMobile) {
|
||||
let touchStartY = 0;
|
||||
let touchStartTime = 0;
|
||||
let touchMoved = false;
|
||||
|
||||
item.addEventListener(
|
||||
'touchstart',
|
||||
(e) => {
|
||||
touchStartY = e.touches[0].clientY;
|
||||
touchStartTime = Date.now();
|
||||
touchMoved = false;
|
||||
this.isScrolling = false;
|
||||
|
||||
// Add visual feedback
|
||||
item.style.transform = 'scale(0.98)';
|
||||
item.style.transition = 'transform 0.1s ease';
|
||||
},
|
||||
{ passive: true }
|
||||
);
|
||||
@ -210,16 +274,55 @@ class CustomChaptersOverlay extends Component {
|
||||
(e) => {
|
||||
const touchMoveY = e.touches[0].clientY;
|
||||
const deltaY = Math.abs(touchMoveY - touchStartY);
|
||||
// If user moved more than 10px vertically, consider it scrolling
|
||||
if (deltaY > 10) {
|
||||
// Use smaller threshold for very small screens to be more sensitive
|
||||
const scrollThreshold = this.isSmallScreen ? 5 : 8;
|
||||
|
||||
if (deltaY > scrollThreshold) {
|
||||
touchMoved = true;
|
||||
this.isScrolling = true;
|
||||
// Remove visual feedback when scrolling
|
||||
item.style.transform = '';
|
||||
}
|
||||
},
|
||||
{ passive: true }
|
||||
);
|
||||
|
||||
item.addEventListener('touchend', seekFn, { passive: false });
|
||||
item.addEventListener('click', seekFn);
|
||||
item.addEventListener(
|
||||
'touchend',
|
||||
(e) => {
|
||||
const touchEndTime = Date.now();
|
||||
const touchDuration = touchEndTime - touchStartTime;
|
||||
|
||||
// Reset visual feedback
|
||||
item.style.transform = '';
|
||||
|
||||
// Only trigger if it's a quick tap (not a scroll)
|
||||
// Use shorter threshold for small screens to feel more responsive
|
||||
const tapThreshold = this.isSmallScreen ? 120 : this.touchThreshold;
|
||||
if (!touchMoved && touchDuration < tapThreshold) {
|
||||
this.handleMobileInteraction(e, chapter, index);
|
||||
}
|
||||
},
|
||||
{ passive: false }
|
||||
);
|
||||
|
||||
item.addEventListener(
|
||||
'touchcancel',
|
||||
() => {
|
||||
// Reset visual feedback on cancel
|
||||
item.style.transform = '';
|
||||
},
|
||||
{ passive: true }
|
||||
);
|
||||
} else {
|
||||
// Desktop click handling
|
||||
item.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
this.player().currentTime(chapter.startTime);
|
||||
this.overlay.style.display = 'none';
|
||||
this.updateActiveItem(index);
|
||||
});
|
||||
}
|
||||
|
||||
anchor.appendChild(drag);
|
||||
anchor.appendChild(meta);
|
||||
@ -238,8 +341,17 @@ class CustomChaptersOverlay extends Component {
|
||||
const chaptersButton = this.player().getChild('controlBar').getChild('chaptersButton');
|
||||
if (chaptersButton) {
|
||||
chaptersButton.off('click');
|
||||
chaptersButton.off('touchstart');
|
||||
|
||||
if (this.isMobile) {
|
||||
// Enhanced mobile button handling
|
||||
chaptersButton.on('touchstart', (e) => {
|
||||
e.preventDefault();
|
||||
this.toggleOverlay();
|
||||
});
|
||||
} else {
|
||||
chaptersButton.on('click', this.toggleOverlay);
|
||||
chaptersButton.on('touchstart', this.toggleOverlay); // mobile support
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -252,6 +364,24 @@ class CustomChaptersOverlay extends Component {
|
||||
this.overlay.style.display = isHidden ? 'block' : 'none';
|
||||
if (el) el.classList.toggle('chapters-open', isHidden);
|
||||
|
||||
// Add haptic feedback on mobile when opening
|
||||
if (this.isMobile && isHidden && navigator.vibrate) {
|
||||
navigator.vibrate(30);
|
||||
}
|
||||
|
||||
// Prevent body scroll on mobile when overlay is open
|
||||
if (this.isMobile) {
|
||||
if (isHidden) {
|
||||
document.body.style.overflow = 'hidden';
|
||||
document.body.style.position = 'fixed';
|
||||
document.body.style.width = '100%';
|
||||
} else {
|
||||
document.body.style.overflow = '';
|
||||
document.body.style.position = '';
|
||||
document.body.style.width = '';
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
this.player()
|
||||
.el()
|
||||
@ -336,6 +466,13 @@ class CustomChaptersOverlay extends Component {
|
||||
this.overlay.style.display = 'none';
|
||||
const el = this.player().el();
|
||||
if (el) el.classList.remove('chapters-open');
|
||||
|
||||
// Restore body scroll on mobile
|
||||
if (this.isMobile) {
|
||||
document.body.style.overflow = '';
|
||||
document.body.style.position = '';
|
||||
document.body.style.width = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -345,6 +482,20 @@ class CustomChaptersOverlay extends Component {
|
||||
}
|
||||
const el = this.player().el();
|
||||
if (el) el.classList.remove('chapters-open');
|
||||
|
||||
// Restore body scroll on mobile when disposing
|
||||
if (this.isMobile) {
|
||||
document.body.style.overflow = '';
|
||||
document.body.style.position = '';
|
||||
document.body.style.width = '';
|
||||
}
|
||||
|
||||
// Clean up event listeners
|
||||
if (this.handleResize) {
|
||||
window.removeEventListener('resize', this.handleResize);
|
||||
window.removeEventListener('orientationchange', this.handleResize);
|
||||
}
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@ -63,7 +63,7 @@
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
bottom: 6px;
|
||||
bottom: 3px;
|
||||
height: 3px;
|
||||
background: #e1002d;
|
||||
border-radius: 2px;
|
||||
@ -77,7 +77,7 @@
|
||||
}
|
||||
|
||||
.video-js .vjs-subs-active button.vjs-subtitles-button::before {
|
||||
width: 24px;
|
||||
width: 20px;
|
||||
transition: none !important;
|
||||
animation: none !important;
|
||||
-webkit-transition: none !important;
|
||||
|
||||
@ -265,6 +265,81 @@ function VideoJSPlayer({ videoId = 'default-video' }) {
|
||||
endTime: '00:00:06.885',
|
||||
chapterTitle: 'A3 Reef Ecosystems',
|
||||
},
|
||||
{
|
||||
startTime: '00:00:06.885',
|
||||
endTime: '00:00:09.180',
|
||||
chapterTitle: 'A4 Coral Formation and Growth',
|
||||
},
|
||||
{
|
||||
startTime: '00:00:09.180',
|
||||
endTime: '00:00:11.475',
|
||||
chapterTitle: 'A5 Tropical Fish Species',
|
||||
},
|
||||
{
|
||||
startTime: '00:00:11.475',
|
||||
endTime: '00:00:13.770',
|
||||
chapterTitle: 'A6 Ocean Current Patterns',
|
||||
},
|
||||
{
|
||||
startTime: '00:00:13.770',
|
||||
endTime: '00:00:16.065',
|
||||
chapterTitle: 'A7 Deep Sea Exploration',
|
||||
},
|
||||
{
|
||||
startTime: '00:00:16.065',
|
||||
endTime: '00:00:18.360',
|
||||
chapterTitle: 'A8 Marine Conservation Efforts',
|
||||
},
|
||||
{
|
||||
startTime: '00:00:18.360',
|
||||
endTime: '00:00:20.655',
|
||||
chapterTitle: 'A9 Underwater Photography Techniques',
|
||||
},
|
||||
{
|
||||
startTime: '00:00:20.655',
|
||||
endTime: '00:00:22.950',
|
||||
chapterTitle: 'A10 Plankton and Microscopic Life',
|
||||
},
|
||||
{
|
||||
startTime: '00:00:22.950',
|
||||
endTime: '00:00:25.245',
|
||||
chapterTitle: 'A11 Whale Migration Routes',
|
||||
},
|
||||
{
|
||||
startTime: '00:00:25.245',
|
||||
endTime: '00:00:27.540',
|
||||
chapterTitle: 'A12 Tidal Pool Ecosystems',
|
||||
},
|
||||
{
|
||||
startTime: '00:00:27.540',
|
||||
endTime: '00:00:29.835',
|
||||
chapterTitle: 'A13 Submarine Technology',
|
||||
},
|
||||
{
|
||||
startTime: '00:00:29.835',
|
||||
endTime: '00:00:32.130',
|
||||
chapterTitle: 'A14 Ocean Pollution Impact',
|
||||
},
|
||||
{
|
||||
startTime: '00:00:32.130',
|
||||
endTime: '00:00:34.425',
|
||||
chapterTitle: 'A15 Bioluminescent Creatures',
|
||||
},
|
||||
{
|
||||
startTime: '00:00:34.425',
|
||||
endTime: '00:00:36.720',
|
||||
chapterTitle: 'A16 Seaweed and Kelp Forests',
|
||||
},
|
||||
{
|
||||
startTime: '00:00:36.720',
|
||||
endTime: '00:00:39.015',
|
||||
chapterTitle: 'A17 Marine Food Chain Dynamics',
|
||||
},
|
||||
{
|
||||
startTime: '00:00:39.015',
|
||||
endTime: '00:00:41.310',
|
||||
chapterTitle: 'A18 Coastal Erosion and Climate Change',
|
||||
},
|
||||
],
|
||||
related_media: [
|
||||
{
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user