import { defineConfig } from 'unocss' import fs from 'fs' import path from 'path' /** * Scans markdown files for VSCode icon patterns used in code blocks. * Icons are referenced with syntax: ~i-vscode-icons:file-type-name~ * * When built through docusaurus-plugin-slidev, uses environment variables: * - SLIDEV_ORIGINAL_SOURCE: Path to the original markdown file * - SLIDEV_ORIGINAL_SOURCE_DIR: Directory containing the source file * - SLIDEV_SITE_DIR: The Docusaurus site directory */ function scanFilesForIcons(): string[] { try { // Try multiple strategies to find markdown files const searchRoots: string[] = [ process.cwd(), path.resolve(process.cwd(), 'slidev'), path.resolve(process.cwd(), '..'), path.resolve(process.cwd(), '.docusaurus'), ] // Add paths from docusaurus-plugin-slidev environment variables if (process.env.SLIDEV_ORIGINAL_SOURCE_DIR) { searchRoots.push(process.env.SLIDEV_ORIGINAL_SOURCE_DIR) } if (process.env.SLIDEV_SITE_DIR) { searchRoots.push(process.env.SLIDEV_SITE_DIR) searchRoots.push(path.resolve(process.env.SLIDEV_SITE_DIR, 'slidev')) } // Pattern to match icon references like ~i-vscode-icons:file-type-ansible~ const iconPattern = /~(i-[a-zA-Z0-9-]+:[a-zA-Z0-9-]+)~/g // Set to store unique icons - include common defaults const icons = new Set([ 'i-vscode-icons:file-type-docker', 'i-vscode-icons:file-type-python', 'i-vscode-icons:file-type-typescript-official', 'i-vscode-icons:file-type-js-official', 'i-vscode-icons:file-type-yaml', 'i-vscode-icons:file-type-json', 'i-vscode-icons:file-type-markdown', 'i-vscode-icons:file-type-vue', 'i-vscode-icons:file-type-html', 'i-vscode-icons:file-type-css', 'i-vscode-icons:file-type-shell', 'i-vscode-icons:file-type-powershell', 'i-vscode-icons:file-type-git', 'i-vscode-icons:file-type-ansible', 'i-vscode-icons:file-type-terraform', 'i-vscode-icons:file-type-kubernetes', ]) // Read the original source file directly if available (from docusaurus-plugin-slidev) if (process.env.SLIDEV_ORIGINAL_SOURCE && fs.existsSync(process.env.SLIDEV_ORIGINAL_SOURCE)) { try { const content = fs.readFileSync(process.env.SLIDEV_ORIGINAL_SOURCE, 'utf-8') let match while ((match = iconPattern.exec(content)) !== null) { if (match[1]) { icons.add(match[1]) } } } catch { // Silently ignore read errors } } // Scan from each root for (const searchRoot of searchRoots) { try { if (!fs.existsSync(searchRoot)) continue // Find all markdown files, excluding node_modules but INCLUDE .docusaurus const slideFiles = fs.globSync('**/*.md', { cwd: searchRoot, exclude: (name) => name === 'node_modules' || name === 'dist' || name === 'build' }).map((f: string) => path.resolve(searchRoot, f)) // Scan each file for icon patterns slideFiles.forEach((file: string) => { try { const content = fs.readFileSync(file, 'utf-8') let match while ((match = iconPattern.exec(content)) !== null) { if (match[1]) { icons.add(match[1]) } } } catch { // Silently ignore read errors } }) } catch { // Silently ignore scan errors } } return Array.from(icons) as string[] } catch { // Return default icon on error return ['i-vscode-icons:file-type-docker'] } } export default defineConfig({ safelist: [ // Dynamically scan for icons in slide files // This returns an array of icon class names that should be included ...scanFilesForIcons() ], })