diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index 2f08b18..392205a 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -34,6 +34,9 @@ jobs: - name: Generate logos.json run: node scripts/scanLogos.js + - name: Generate SVG variants + run: node scripts/generate-svg-variants.js + - name: Prepare Pages artifact run: | mkdir -p ./gh-pages-artifact/build diff --git a/Makefile b/Makefile index 663e240..1720ee6 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ CONTAINER_NAME = slogos-dev DEV_PORT = 5006 # Main targets -.PHONY: all build start stop restart logs clean scan-logos dev rebuild favicon deps-favicon build-with-favicons sync-packages convert-colors +.PHONY: all build start stop restart logs clean scan-logos dev rebuild favicon deps-favicon build-with-favicons sync-packages convert-colors generate-svg-variants all: build start @@ -75,3 +75,9 @@ update-lock: @echo "Updating package-lock.json to match package.json..." $(DOCKER_COMPOSE) -f compose.dev.yml run --rm $(CONTAINER_NAME) npm install @echo "Package lock file has been updated" + +# Generate SVG variants with color sets +generate-svg-variants: + @echo "Generating SVG variants with color sets..." + $(DOCKER_COMPOSE) -f compose.dev.yml run --rm $(CONTAINER_NAME) node scripts/generate-svg-variants.js + @echo "SVG variants have been generated" diff --git a/package.json b/package.json index 082a637..b166d2e 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,9 @@ "dev": "rollup -c -w", "start": "sirv public --host 0.0.0.0 --dev --single", "scan-logos": "node scripts/scanLogos.js", - "generate-favicons": "node scripts/generateFavicons.js" + "generate-favicons": "node scripts/generateFavicons.js", + "generate-variants": "node scripts/generate-svg-variants.js", + "variants": "npm run generate-variants" }, "devDependencies": { "@rollup/plugin-commonjs": "^17.0.0", diff --git a/public/data/logos.json b/public/data/logos.json index 9d3a7b6..1509334 100644 --- a/public/data/logos.json +++ b/public/data/logos.json @@ -2361,4 +2361,4 @@ ], "brand": "Bvr" } -] +] \ No newline at end of file diff --git a/scripts/generate-svg-variants.js b/scripts/generate-svg-variants.js new file mode 100644 index 0000000..cb37972 --- /dev/null +++ b/scripts/generate-svg-variants.js @@ -0,0 +1,190 @@ +#!/usr/bin/env node + +const fs = require('fs'); +const path = require('path'); + +const LOGOS_DIR = path.join(__dirname, '..', 'public', 'logos'); +const LOGOS_GEN_DIR = path.join(__dirname, '..', 'public', 'logos_gen'); + +// Try multiple possible locations for logos.json +const POSSIBLE_LOGOS_JSON_PATHS = [ + path.join(process.cwd(), 'public', 'data', 'logos.json'), // Correct location after scan-logos + path.join(__dirname, '..', 'public', 'data', 'logos.json'), + path.join(process.cwd(), 'public', 'logos.json'), + path.join(__dirname, '..', 'public', 'logos.json'), + path.join(__dirname, '..', 'src', 'data', 'logos.json') +]; + +function findLogosJsonPath() { + for (const possiblePath of POSSIBLE_LOGOS_JSON_PATHS) { + if (fs.existsSync(possiblePath)) { + console.log(`šŸ“ Found logos.json at: ${possiblePath}`); + return possiblePath; + } + } + + console.error('āŒ Could not find logos.json in any of these locations:'); + POSSIBLE_LOGOS_JSON_PATHS.forEach(p => console.error(` ${p}`)); + return null; +} + +/** + * Load logos data from logos.json + */ +function loadLogosData() { + const LOGOS_JSON_PATH = findLogosJsonPath(); + + if (!LOGOS_JSON_PATH) { + console.error('āŒ logos.json file not found'); + process.exit(1); + } + + try { + const data = fs.readFileSync(LOGOS_JSON_PATH, 'utf8'); + return JSON.parse(data); + } catch (error) { + console.error('Error loading logos.json:', error.message); + process.exit(1); + } +} + +/** + * Apply color set to SVG content + */ +function applySvgColors(svgContent, colorSet, targets) { + let modifiedSvg = svgContent; + + if (!targets || !colorSet) { + return modifiedSvg; + } + + // Apply colors based on targets mapping + Object.entries(targets).forEach(([targetKey, selector]) => { + if (colorSet[targetKey]) { + const color = colorSet[targetKey]; + + // Handle different types of selectors + if (selector.startsWith('#')) { + // ID selector - replace fill/stroke for specific element + const elementId = selector.substring(1); + const idRegex = new RegExp(`(id="${elementId}"[^>]*?)fill="[^"]*"`, 'g'); + modifiedSvg = modifiedSvg.replace(idRegex, `$1fill="${color}"`); + + // If no fill attribute, add it + const addFillRegex = new RegExp(`(id="${elementId}"[^>]*?)(?!.*fill=)([^>]*>)`, 'g'); + modifiedSvg = modifiedSvg.replace(addFillRegex, `$1 fill="${color}"$2`); + } else { + // Default: replace all fill attributes (fallback) + modifiedSvg = modifiedSvg.replace( + /fill="[^"]*"/g, + `fill="${color}"` + ); + } + } + }); + + return modifiedSvg; +} + +/** + * Generate SVG variants with color sets + */ +function generateSvgVariants() { + console.log('šŸŽØ Generating SVG variants with color sets...'); + + // Ensure the logos_gen directory exists + if (!fs.existsSync(LOGOS_GEN_DIR)) { + fs.mkdirSync(LOGOS_GEN_DIR, { recursive: true }); + console.log(`šŸ“ Created directory: ${LOGOS_GEN_DIR}`); + } + + const logos = loadLogosData(); + let generatedCount = 0; + let skippedCount = 0; + + if (!Array.isArray(logos)) { + console.error('āŒ Expected logos.json to contain an array, got:', typeof logos); + process.exit(1); + } console.log(`šŸ“Š Processing ${logos.length} logos...`); + + logos.forEach((logo, index) => { + // Check if logo has required properties + if (!logo || typeof logo !== 'object') { + console.warn(`āš ļø Logo at index ${index} is not a valid object`); + skippedCount++; + return; + }// Handle different possible filename properties + const pathOrFilename = logo.path || logo.filename || logo.file || logo.name; + + if (!pathOrFilename) { + console.warn(`āš ļø Logo at index ${index} has no path/filename property`); + skippedCount++; + return; + } + + // Extract just the filename from path if needed + const actualFilename = pathOrFilename.includes('/') ? path.basename(pathOrFilename) : pathOrFilename; + + // Skip if no sets or not an SVG + if (!logo.sets || !actualFilename.endsWith('.svg')) { + skippedCount++; + return; + } + + const basePath = path.join(LOGOS_DIR, actualFilename); + const baseNameWithoutExt = path.basename(actualFilename, '.svg'); // Check if base SVG exists + if (!fs.existsSync(basePath)) { + console.warn(`āš ļø Base SVG not found: ${actualFilename}`); + skippedCount++; + return; + } + + // Read the base SVG content + const baseSvgContent = fs.readFileSync(basePath, 'utf8'); + + // Generate variants for each color set + // Handle sets as object (not array) + Object.entries(logo.sets).forEach(([setName, setConfig]) => { + if (!setName || !setConfig) { + console.warn(`āš ļø Invalid set in ${actualFilename}: missing name or config`); + return; + } + + // Convert set config to colors object + const colors = {}; + if (logo.colors && logo.targets) { + Object.entries(setConfig).forEach(([targetKey, colorKey]) => { + if (logo.colors[colorKey]) { + colors[targetKey] = logo.colors[colorKey]; + } + }); + } + + if (Object.keys(colors).length === 0) { + console.warn(`āš ļø No valid colors found for set ${setName} in ${actualFilename}`); + return; + } const variantFilename = `${baseNameWithoutExt}__${setName}.svg`; + const variantPath = path.join(LOGOS_GEN_DIR, variantFilename); + + // Apply colors to SVG + const modifiedSvg = applySvgColors(baseSvgContent, colors, logo.targets); + + // Write the variant SVG + fs.writeFileSync(variantPath, modifiedSvg, 'utf8'); + + console.log(`āœ… Generated: ${variantFilename}`); + generatedCount++; + }); + }); + + console.log(`\nšŸŽØ SVG variant generation complete!`); + console.log(` Generated: ${generatedCount} variants`); + console.log(` Skipped: ${skippedCount} logos (no sets or not SVG)`); +} + +// Run the script +if (require.main === module) { + generateSvgVariants(); +} + +module.exports = { generateSvgVariants };