@devbookhq/docusaurus-code-video-plugin
Version:
Add a video to a Docusaurus code block and highlight code lines as the video plays.
78 lines (77 loc) • 2.3 kB
JavaScript
import { useCallback, useMemo, useState, } from 'react';
function convertHMSToSeconds(hms) {
const [s, m, h] = hms.split(':').reverse();
let time = 0;
if (s) {
const seconds = parseInt(s);
if (!Number.isNaN(seconds)) {
time += seconds;
}
}
if (m) {
const minutes = parseInt(m);
if (!Number.isNaN(minutes)) {
time += minutes * 60;
}
}
if (h) {
const hours = parseInt(h);
if (!Number.isNaN(hours)) {
time += hours * 60 * 60;
}
}
return time;
}
function notEmpty(value) {
return value !== null && value !== undefined;
}
function getHighlight(time, timeMap) {
const interval = timeMap.find(i => i.start <= time && i.end > time);
return interval?.highlightString;
}
const intervalHighlightPropRegex = /^(.+:.+)-(.+:.+)$/;
function getTimeMap(props) {
return Object
.entries(props)
.map(([key, value]) => {
const found = key.match(intervalHighlightPropRegex);
if (!found)
return;
const startString = found[1];
const endString = found[2];
if (!startString || !endString)
return;
return {
start: convertHMSToSeconds(startString),
end: convertHMSToSeconds(endString),
highlightString: value.replace('(', '{').replace(')', '}'),
};
})
.filter(notEmpty);
}
function useVideoHighlight(props) {
const [highlightString, setHighlightString] = useState();
const timeMap = useMemo(() => {
const newTimeMap = getTimeMap(props);
return newTimeMap.length > 0 ? newTimeMap : undefined;
}, [props]);
const handleTimeChange = useCallback((time) => {
if (!timeMap)
return;
const highlight = getHighlight(time, timeMap);
setHighlightString(highlight);
}, [timeMap]);
const metastring = highlightString
? `${highlightString} ${props.metastring}`
: props.metastring;
return useMemo(() => ({
metastring,
handleTimeChange: timeMap ? handleTimeChange : undefined,
hasHighlight: !!timeMap
}), [
metastring,
handleTimeChange,
timeMap,
]);
}
export default useVideoHighlight;