/** * Slugify function, has to match the formula used in interactive-tutorial.js */ import { useEffect, useState } from 'react' export const useThemeFromClassList = (classNames) => { const [currentTheme, setCurrentTheme] = useState(null) useEffect(() => { // Function to update the theme based on the class list const updateTheme = () => { for (const className of classNames) { if (document.documentElement.classList.contains(className)) { setCurrentTheme(className) return } } } // Initial update updateTheme() // Create an observer instance linked to the callback function const observer = new MutationObserver(() => { updateTheme() }) // Start observing the target node for configured mutations observer.observe(document.documentElement, { attributes: true, // Listen for attribute changes attributeFilter: ['class'], // Specifically, listen only to "class" attribute changes }) // Cleanup: Disconnect the observer return () => { observer.disconnect() } }, [classNames]) return currentTheme } export function slugify(s) { const unacceptable_chars = /[^A-Za-z0-9._ ]+/g const whitespace_regex = /\s+/g s = s.replace(unacceptable_chars, '') s = s.replace(whitespace_regex, '_') s = s.toLowerCase() if (!s) { s = '_' } return s } export function idify(s: string) { // like slugify, but more unicode-friendly. // for some reason the better version using \p gives an "s12 is undefined" TypeError sometimes, // so it's disabled for now. With that fixed, we could use localized step names in interactive tutorials. //s = s.replace(/[^\p{Alphabetic}\p{Mark}\p{Decimal_Number}\p{Connector_Punctuation}\p{Join_Control}]/gu, '').trim().toLowerCase() //s = s.replace(/[^\w\s-]/gu, '').trim().toLowerCase() s = s .replace(/([^\w]|[\s-])/gu, '') .trim() .toLowerCase() s = s.replace(/[\s-]+/gu, '-') if (!s) { s = '_' } return s }