UNPKG

@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
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;